/*
usb gadget驱动与 gadget框架间的关系:
1. gadget驱动提供的设备描述符,仅仅是包含pid和vid等少量信息.
bMaxPacketSize0 为gadget框架根据该usb device控制器的ep0的最大包大小进行设置;
bNumConfigurations 为gadget框架根据配置描述符数组中已加入的描述符数量进行设置;

2. gadget驱动提供的struct usb_function.set_alt()函数, 是在gadget框架收到usb host发来请求设置配置描述符后,
根据所请求的描述符index,从配置描述符数组中找到下标为index的配置描述符, 对配置描述符之下的接口描述符一一进行初始化.
一般而言, 一个接口描述符对应着一个function, 对应着struct usb_function 结构体.

3. ep0 端点由gadget框架接管, 未加入ep_list中, 而分配给gadget驱动的ep都从ep_list中获取. 既然ep0 由gadget框架使用, 
因此枚举过程全程由gadget框架负责, 将gadet驱动提供的描述符发送给usb host.

*/

/*
 *
 usb gadget框架, usb device控制器和gadget_zero功能的代码流程总结:

 1.初始化
    1.1 usb device 控制器系统初始化
        usba_udc_probe():
        读取dts, 获得控制器寄存器的地址,和ep读写内存的地址.获得vbus引脚gpio号并注册中断, 用于检查设备的插拔. 获得控制器中断号,用于处理控制器状态变化,ep读写等中断. 获取usb_id引脚的gpio号并注册中断. 获取端点的数量,以及端点支持的能力.

usba_udc_probe()
    ->读取dts, 获得控制器寄存器的地址,和ep数据内存的地址,获取控制器irq号. 为struct usba_udc *udc_a 分配内存.
    ->atmel_udc_of_init()
        ->读取dts, 获得usb_vbus和usb_id引脚的gpio号, 获取所有端点的信息,包含每个端点支持的能力. 当前usb device控制器拥有16个端点. 为udc_a->usba_ep数组分配内存, 根据dts的信息填充usba_ep数组. usba_ep[0]->ep作为控制端点供枚举流程使用, usba_ep[1~15]->ep可供用户编程使用. 将usba_ep[1~15]->ep添加进ep_list列表.
    ->注册控制器的irq中断服务函数, 用于处理控制器的状态变化,ep收发等中断. 注册usb_vbus引脚中断,处理设备的拔插. 注册usb_id引脚中断, 处理id引脚的电平, 开关usb_host的vbus的电压输出.
    ->usb_add_gadget_udc()
        ->usb_add_gadget_udc_release()
           ->为 struct usb_udc	*udc分配内存, 将udc添加进udc_list列表.

usb_composite_probe()
    ->usb_gadget_probe_driver()
        -> 遍历 udc_list列表, 找到udc->driver为NULL的udc结构体.
        ->udc_bind_to_driver()
            ->driver->bind() ==> composite_bind()
            ->为struct usb_composite_dev *cdev分配内存.
            ->composite_dev_prepare()
                ->设置cdev->req, 该req用于设备枚举流程的数据传输.为cdev->req->buf分配内存.
            ->composite->bind() ==> zero_bind()
                #注释: loopback_driver 是包含纯粹的配置描述符的信息,func_lb则是包含每个接口描述符的信息. 每个接口描述符紧跟着还有还有端点描述符的信息.
                ->usb_add_config_only(cdev, &loopback_driver)
                    -> 将loopback_driver 加入cdev->configs列表. loopback_driver包含配置描述符的部分头部信息.
                ->usb_add_function(&loopback_driver, func_lb)
                    ->将func_lb加入loopback_driver->functions列表.
                    ->function->bind() ==> loopback_bind()
                        ->usb_interface_id()
                            -> 将func_lb 指针复制到 loopback_driver->interface[x]. x从0开始计数. 多次调用usb_add_function(), 就可以向interface[]数组添加更多的functions,即接口描述符+端点描述符.
                        ->usb_ep_autoconfig()
                            ->根据端点描述符从ep_list列表内,找到符合的,未被使用的ep, 并根据端点描述符设置改ep的地址.
                        ->usb_assign_descriptors()
                            ->将设备的接口描述符,端点描述符复制到func_lb.
            ->usb_gadget_udc_start()
                ->udc->gadget->ops->udc_start ==> atmel_usba_start()
                    ->获取usb_vbus引脚的电压,高电平为已经接入设备.那么将执行 usba_start()函数去初始化usb device控制器. 当前电压为低电平.

设备接入主机后,引发中断:
usba_vbus_irq_thread()
    -> 使能时钟. 使能控制器, 使能写控制器寄存器功能. 使能控制器reset完成中断, 即控制器reset完成后,将发出中断.

控制器reset完成后:
usba_udc_irq()
    ->if (status & USBA_END_OF_RESET)
        ->清楚中断标志位. 写寄存器,设置端点0属性:最大包大小64,类型为控制端点. 使能端点0 RX_setup中断, 即端点0收到控制传输的SETUP包时将发出中断. 使能 suspend中断, 使能resume 完成中断, 使能ep0 中断.

控制器suspend完成后:
usba_udc_irq()
    -> 清除中断标志位

ep0 接收到控制传输的SETUP包:
usba_udc_irq()
    ->if (ep_status)
        -> 遍历udc_a->usba_ep数组, 找到类型为控制端点的ep, 都执行usba_control_irq()函数. 当前找到的ep为 struct usba_ep eps[0]
        ->usba_control_irq()
            -> 读取端点状态寄存器, 判断RX_SETUP位, 值为1继续执行.
                ->从eps[0]->fifo获取host发来的数据,数据内容为:
                bRequestType 0x80. bRequest 0x06, wValue 0x100length 64
                即host请求设备描述符.
                清除RX_SETUP中断标志位.
                    -> 判断当前ep的索引值, 为0代表时默认用于控制传输的ep0, 则继续执行下面代码.
                        ->handle_ep0_setup()
                            ->switch (crq->bRequest) {
                              default:
                                ->udc->driver->setup() ==> composite_setup()
                                    -> 根据ep获得的数据ep->fifo, 判断此次host获取描述符的请求是要获取设备描述符.
                                        -> 将根据配置描述符数量,ep0最大包大小等数据构建的cdev->desc设备描述符 复制到 cdev->req->buf. buf的内存在composite_dev_prepare()内被分配.
                            -> 判断ep要发送的数据长度大于等于0, 继续执行
                                ->若长度为0,就要设置为要发送0长数据包,以告诉host数据传输完毕.
                                ->composite_ep0_queue()
                                    ->usb_ep_queue()
                                        ->ep->ops->queue() ==> usba_ep_queue()
                                            ->将cdev->req 添加进struct usba_ep *eps[0]->queue列表.
                                            -> 写控制器寄存器, 使能tx包准备完成中断.
                        

ep0 IN数据包准备完成中断发生, 即要发送给host的数据包准备好了:
usba_udc_irq()
    ->if (ep_status)
        -> 遍历udc_a->usba_ep数组, 找到类型为控制端点的ep, 都执行usba_control_irq()函数.
        ->usba_control_irq()
            -> 读取端点状态寄存器的值. 从struct usba_ep *eps[0]->queue列表中取出一个req.
            -> 判断端点状态寄存器的tx包准备完成中断标志位(USBA_TX_PK_RDY)值为1, 则继续执行.
                ->submit_request()
                    ->next_fifo_transaction()
                        ->将req->buf的数据复制到struct usba_ep eps[0]->fifo 内.
                        -> 写控制器寄存器, 使能tx包准备完成中断.
                    ->判断req->last_transaction, 值为1, 代表所有数据都复制到eps[0]->fifo.  值为1, 则继续执行.
                        -> 关闭tx包准备完成中断(USBA_TX_PK_RDY), 使能IN数据传输完成中断, 即数据向host发送完成时,将发出中断.
            -> 读端点控制寄存器, 判断 USBA_TX_COMPLETE 标志位. 即IN数据传输完成后的中断标志位. 值为1, 继续执行.
                ->根据端点状态寄存器, 判断当前控制传输处于数据IN阶段
                  switch (ep->state) {
                      case DATA_STAGE_IN: 
                   -> 使能OUT数据接收中断, 即当从host接收到数据时将发出中断. 关闭IN数据发生中断.
            -> 读端点控制寄存器, 判断 USBA_RX_BK_RDY 标志位. 即OUT数据接收完成后的中断标志位. 值为1, 继续执行.
                ->根据端点状态寄存器, 判断当前控制传输处于数据OUT阶段
                    switch (ep->state) {
                        case STATUS_STAGE_OUT:
                    -> 关闭OUT数据接收完成中断. 清除OUT数据接收完成中断标志位. 将req从eps[0]->queue队列中移除.


再次发生控制器reset完成中断:
        
ep0 接收到控制传输的SETUP包:
usba_udc_irq()*
    ->if (ep_status)
    # 与上一次接收到setup包的流程相似,但这次为host请求设置设备地址.将省略类似的代码.
        ->switch (crq->bRequest) {
             case USB_REQ_SET_ADDRESS:
            ->写控制器寄存器, 设置设备地址.使能IN数据输出完成中断.
 
发生IN数据传输完成中断:
usba_udc_irq()
    ->if (ep_status)
        -> 判断当前端点寄存器的 IN数据传输完成中断标志位位1.
          if ((epstatus & epctrl) & USBA_TX_COMPLETE)
           ->switch (ep->state) {
                 case STATUS_STAGE_ADDR:
                -> 写控制器寄存器, 使能设备地址.

ep0 接收到控制传输的SETUP包:
usba_udc_irq()
    ->if (ep_status)
    # 此次host再次请求设备描述符, 不再重复描述.

ep0 接收到控制传输的SETUP包, 此次时获取配置描述符:
usba_udc_irq()
    ->if (ep_status)
        ->usba_control_irq()
            -> 从eps[0]->fifo获取host发来的数据.
            ->handle_ep0_setup()
                ->udc->driver->setup() ==> composite_setup()
                     ->case USB_REQ_GET_DESCRIPTOR:
                          switch (w_value >> 8) {
                              case USB_DT_CONFIG:
                         -> 从eps[0]->fifo中,得知host希望获取的配置描述符的编号(w_index的低8位). 遍历cdev->configs队列,找到第x个()的配置(config).
                            ->config_buf()
                                -> 将配置描述符(config)的内容复制到cdev->req->buf内. 遍历config->functions列表, 找到匹配gadget->speed的function(包含接口描述符和端点描述符), 将function的内容复制到cdev->req->buf.
                    ->usb_ep_queue()
                        ->将cdev->req 加入eps[0]->queue列表
     # 接下来就是将cdev->req->buf的内容复制到eps[0]->fifo,发送给host

ep0 接收到控制传输的SETUP包, 此次依旧是获取配置描述符. 上一次只是获取描述符而已. 这一次获取描述符+接口,端点描述符. 不进行重复描述.

ep0 收到控制传输的SETUP包, 此次host请求设置配置描述符.
usba_udc_irq()
    ->if (ep_status)
        ->usba_control_irq()
            ->handle_ep0_setup()
                ->composite_setup()
                     ->switch (ctrl->bRequest) {
                        case USB_REQ_SET_CONFIGURATION:
                            -> 遍历cdev->configs列表所有的配置, 找到对应host请求编号的config. 遍历config->interface[]数组内所有的描述符,对与接口描述符则执行其set_alt()函数,进行接口的初始化.该函数由gadget设备驱动定义,即由用户定义.

                               ->f->set_alt() ==> loopback_set_alt()
                                    ->enable_endpoint()
                                        ->usb_ep_enable()
                                             ->ep->ops->enable ==> usba_ep_enable()
                                                -> 根据loopback->in_ep 和 loopback->out_ep 找到对应的物理端点寄存器, 使能对应端点. 根据端点描述符, 设置端点的最大包大小,端点传输方向, 端点类型.
                                    ->alloc_requests()
                                        -> 为loopback->in_req 和out_ereq成员分配内存, 为xx_req->buf分配内存. 设置xx_req->comlete数据传输完成函数(当buf接收到数据,或数据传输为host之后,会执行该函数) 为loopback_complete().
                                        ->usb_ep_queue()
                                            -> 将xx_req加入loopback->xx_ep->queue队列内. 等待数据接收或被传输至host..

epx 端点发生中断, 是host有批量传输的请求.
usba_udc_irq()
	-> if (dma_status) {
        -> 遍历所有端点,读取对应端点的状态寄存器, 判断是否该端点发生数据传输的中断.
            从xx_ep->queue队列取出位于队首的req, 将它移除队列. 执行该req->complete()函数.


usb device 控制器寄存器说明:
usba_start()
CTRL    USBA_ENABLE_MASK  使能控制器, 使能写控制器寄存器功能
INT_ENB USBA_END_OF_RESET  控制器reset 完成时, 引发中断

usba_udc_irq()
INT_STA USBA_DET_SUSPEND 控制器suspend 完成标志位
        DMA_INT  DMA中断发生标志位
        EPT_INT  端点中断标志位
        USBA_END_OF_RESET 控制器reset完成标志位
        USBA_HIGH_SPEED 控制器的工作速度,满速或高速

if (status & USBA_DET_SUSPEND)
INT_CLR USBA_DET_SUSPEND 清除INT_STA寄存器的中断标志位

if (dma_status)
DMA CONTROL   USBA_DMA_END_TR_IE 数据传输完成时产生中断
              USBA_DMA_CH_EN  使能该DMA通道
              USBA_DMA_END_BUF_IE  data 全部传输完成会产生中断
              USBA_DMA_END_BUF_EN

if (ep_status)

EP STA  USBA_RX_SETUP 端点收到控制传输的SETUP包
        USBA_TX_PK_RDY 向host发送的数据包准备完成.

EP CTL USBA_TX_PK_RDY   向host发送的数据包准备完成时, 将发出中断

ep CLR_STA USBA_RX_SETUP  清除 UDPHS_EPTSTAx 寄存器中的 RX_SETUP 标志位

EP CTL_ENB  USBA_TX_PK_RDY 使能tx包准备ok,和tx传输错误中断
            USBA_EPT_ENABLE 根据设备描述符 使能该端点
            USBA_RX_SETUP 使能 RX_SETUP 中断
         
EP SET_STA USBA_TX_PK_RDY 表示ep->fifo已经写入数据, 可以进行数据传输
            USBA_TX_COMPLETE 使能 IN data 传输完成中断

EP CTL_DIS USBA_TX_PK_RDY  关闭tx包准备OK, 和tx传输错误中断
           USBA_TX_COMPLETE 关闭 IN data 传输完成 中断

EP CFG  USBA_EPT_TYPE_BULK 端点类型:   批量端点
        USBA_BK_NUMBER_DOUBLE
        USBA_EPT_DIR_IN  方向为向host发送数据
	    USBA_EPT_TYPE_CONTROL 控制端点
		USBA_BK_NUMBER_ONE 

if (status & USBA_END_OF_RESET)

int_enb USBA_DET_SUSPEND:  使能 suspend 中断
        USBA_END_OF_RESUME: 使能 END of resume 中断. resume完成后引发中断
        EPT_0:  使能 ep0 中断


usb gadget 驱动编写注意事项:
1. struct usb_request *req.
    req->complete 该函数指针必须被设置, gadget框架在调用它时并没有检查其有效性.
2. usb_ep_queue() 不能对一个端点连续多次使用. 由于该函数有将 struct usb_request *req->buf 的数据写入当前端点的fifo寄存器或dma buf地址寄存器的操作,
    因此多次调用该函数后, 最终仅仅是最后一次的调用有效. 每个端点的fifo寄存器或dma buf地址寄存器是独立的,各自调用usb_ep_queue()并不影响.
3. usb_eq_queue()正确调用方法:
   req = alloc_ep_req(xxx) 分配req.
   req->complete = out_complete; 必须设置complete()函数
   usb_ep_queue(ep, req);    将req加入该ep的队列内.

   当req->buf的数据发送给host,或从host发来数据,产生中断, 调用req->complete().

   req->complete()
   那么在comlete()函数内, 可以再次分配一个req,或继续使用当前req, 执行usb_ep_queue()将req加入队列.
   设置req->complete()指向不同的函数, 以匹配不同的传输流程.

*/
struct platform_device *pdev <tag2>
    ->struct device	dev;
        ->void *driver_data; <tag3> <point to obj1>

struct usba_udc *udc; <tag1> <obj1>
	->struct usba_ep *usba_ep; <<tag59> <point to obj19>>
   	->void __iomem *fifo;  <tag56> <"指向寄存器内存">
	->struct usb_gadget gadget; <obj3> <tag53> <copy from obj14>
	    ->struct usb_ep			*ep0; <tag5> <point to obj2>
	    ->struct list_head		ep_list; <list1>
	    ->struct usb_udc			*udc; <tag12> <point to obj4>
	    ->struct device			dev;
            ->void *driver_data; <tag15> <point to obj5>

static struct usb_gadget usba_gadget_template = { <obj14>
	.ops		= &usba_udc_ops,
	.max_speed	= USB_SPEED_HIGH,
	.name		= "atmel_usba_udc",
};

struct usba_ep *eps; <tag4> <obj19>
    ->struct usba_udc	*udc; <tag6> <point to obj1>
    =>eps[1~15]
	    ->void __iomem		*fifo;  <<tag57><"指向寄存器内存">>
        ->struct usb_ep ep;
	        ->struct usb_ep_caps	caps; <tag7>
	        ->struct list_head	ep_list; <tag9> <add to list1>
    =>eps[0]
	    ->void __iomem		*fifo;  <<tag57><"指向寄存器内存">>  <<tag39> <copy from obj12>>
	    ->struct list_head			queue; <list5>
        ->struct usb_ep ep; <obj2>
            ->struct usba_udc	*udc; <tag6> <point to obj1>
            ->caps.type_control = true; <tag8>
            ->void			*driver_data; <tag20> <point to obj5>
            ->const struct usb_endpoint_descriptor	*desc; <tag31> <point to obj9>

static struct usb_endpoint_descriptor usba_ep0_desc; <obj9>

struct usb_udc		*udc; <tag10> <obj4>
	->struct usb_gadget		*gadget; <tag11> <point to obj3>
	->struct list_head		list; <tag58> <add to list2>

struct list_head udc_list; <list2>

struct usb_composite_dev	*cdev; <tag13> <obj5>
	->struct usb_device_descriptor	desc; <tag35> <set desc> <obj10>
	->struct list_head		configs; <list3>
	->struct usb_gadget		*gadget; <tag14> <point to obj3>
	->struct usb_request		*req; <tag16> <point to obj11>
	->struct usb_configuration	*config; <tag44> <point to obj6>


struct usba_request *cdev_req; <tag37>
	->struct list_head			queue; <tag38> <add to tail list5> <tag40> <remove from list5> <tag42> <add to tail list5>
	->struct usb_request	req; <obj11>
	    ->void			*buf; <tag17> <<tag36> <copy from obj10>> <obj12> <<tag43> <copy from obj6>>
	    ->void			*context; <tag18> <point to obj5>

struct f_loopback	*loop; <tag21>
	->struct usb_ep		*in_ep; <tag28> <get from list1>
	    ->const struct usb_endpoint_descriptor	*desc; <tag46> <point to obj15>
	    ->unsigned		maxpacket:16; <tag47>
	->struct usb_ep		*out_ep; <tag29> <get from list1>
	    ->const struct usb_endpoint_descriptor	*desc; <tag46> <point to obj16>
	    ->unsigned		maxpacket:16; <tag47>
	->struct usb_function	function; <tag24> <func_lb> <obj7>
	    ->struct usb_configuration	*config; <tag25> <point to obj6>
	    ->struct list_head		list; <tag26> <add to list4>
	    ->struct usb_descriptor_header	**hs_descriptors; <tag30> <copy fomr obj8>
        /* 通过位域值 表示哪个端点被使用了. */
	    ->DECLARE_BITMAP(endpoints, 32); <tag45>

static struct usb_configuration loopback_driver; <obj6>
	->struct usb_composite_dev	*cdev; <tag22> <point to obj5>
	->struct list_head	list; <tag23> <add to list3>
	->struct list_head	functions; <list4>
	->struct usb_function	*interface[MAX_CONFIG_INTERFACES];
        =>interface[0] <tag27> <point to obj7>

static struct usb_descriptor_header *hs_loopback_descs[]; <obj8>
{
	(struct usb_descriptor_header *) &loopback_intf,
	(struct usb_descriptor_header *) &hs_loop_source_desc, <obj15>
	(struct usb_descriptor_header *) &hs_loop_sink_desc, <obj16>
	NULL,
};

struct usba_request *a_in_req; <tag48>
	->struct usb_request	req;
	    ->void		*buf; <tag51>  <point to obj18>
	    ->void			*context;
struct usba_request *a_out_req; <tag49>
	->struct usb_request	req;
	    ->void		*buf; <tag50> <obj18>
	    ->void			*context;

INT_ENB  ==> UDPHS_IEN ==> UDPHS Interrupt Enable Register

INT_CLR  ==> USBA_INT_CLR ==>  UDPHS Clear Interrupt Register

INT_STA ==> USBA_INT_STA ==> UDPHS Interrupt Status Register

CTRL  ==> UDPHS_CTRL ==>  UDPHS Control Register
===================ep reg=================
CFG ==>  UDPHS_EPTCFG ==>  UDPHS Endpoint Configuration Register

CTL_ENB ==> UDPHS_EPTCTLENB ==> UDPHS Endpoint Control Enable Register

STA ==>  UDPHS_EPTSTA ==> UDPHS Endpoint Status Register

CTL ==> UDPHS_EPTCTL ==> UDPHS Endpoint Control Register

UDPHS_EPTCLRSTA ==> UDPHS Endpoint Clear Status Register

SET_STA  ==> UDPHS_EPTSETSTA ==> UDPHS Endpoint Set Status Register

CTL_DIS  ==>  UDPHS_EPTCTLDIS ==> UDPHS Endpoint Control Disable Register

CLR_STA ==> UDPHS_EPTCLRSTA ==> UDPHS Endpoint Clear Status Register
==================end ep reg=============

USBA_END_OF_RESET

USBA_DET_SUSPEND

ep_status 0x1

USBA_END_OF_RESET

ep_status 0x1

USBA_NR_DMAS

USBA_NR_DMAS

===================dma reg================
ADDRESS ===> UDPHS_DMAADDRESS ==> UDPHS DMA Channel Address Register
CONTROL ===> UDPHS_DMACONTROL ===>  UDPHS DMA Channel Control Register
STATUS ===> UDPHS_DMASTATUS ===>  UDPHS DMA Channel Status Register


====================end dma reg =================

static int __init usb_udc_init(void)
{
    return 0;
}

static int __init gadget_cfs_init(void)
{
    return 0;
}

/* 控制器函数:  读取dts信息, 注册vbus, id等gpio的irq.
 * 新建udc 加入 gadget框架的udc_list.*/
static int usba_udc_probe(struct platform_device *pdev) <tag2>
{
	struct resource *regs, *fifo;
	struct clk *pclk, *hclk;
	struct usba_udc *udc;
	int irq, ret, i;

	udc = devm_kzalloc(&pdev->dev, sizeof(*udc), GFP_KERNEL); <tag1>

	udc->vbus_detect_on = false;
	udc->gadget = usba_gadget_template; <tag53>
	INIT_LIST_HEAD(&udc->gadget.ep_list);

	regs = platform_get_resource(pdev, IORESOURCE_MEM, CTRL_IOMEM_ID);
	fifo = platform_get_resource(pdev, IORESOURCE_MEM, FIFO_IOMEM_ID);

	irq = platform_get_irq(pdev, 0);

	pclk = devm_clk_get(&pdev->dev, "pclk");
	hclk = devm_clk_get(&pdev->dev, "hclk");

	spin_lock_init(&udc->lock);
	mutex_init(&udc->vbus_mutex);
	udc->pdev = pdev;
	udc->pclk = pclk;
	udc->hclk = hclk;

	ret = -ENOMEM;
	udc->regs = devm_ioremap(&pdev->dev, regs->start, resource_size(regs));

	udc->fifo = devm_ioremap(&pdev->dev, fifo->start, resource_size(fifo)); <tag56>

	platform_set_drvdata(pdev, udc); <tag3>
    static inline void platform_set_drvdata(struct platform_device *pdev,
                        void *data)
    {
        dev_set_drvdata(&pdev->dev, data);
        static inline void dev_set_drvdata(struct device *dev, void *data)
        {
            dev->driver_data = data;
        }
    }

	/* Make sure we start from a clean slate */
	ret = clk_prepare_enable(pclk);

	clk_disable_unprepare(pclk);

	udc->usba_ep = atmel_udc_of_init(pdev, udc); <tag59>
    static struct usba_ep * atmel_udc_of_init(struct platform_device *pdev,
                                struct usba_udc *udc)
    {
        u32 val;
        const char *name;
        struct device_node *np = pdev->dev.of_node;
        const struct of_device_id *match;
        struct device_node *pp;
        int i, ret;
        struct usba_ep *eps, *ep;

        match = of_match_node(atmel_udc_dt_ids, np);

        udc->errata = match->data;

        udc->num_ep = 0;

        udc->id_pin = devm_gpiod_get_optional(
                &pdev->dev, "atmel,id", GPIOD_IN);
        udc->vbus_pin = devm_gpiod_get_optional(
                &pdev->dev, "atmel,vbus", GPIOD_IN);
        udc->vbus_en_pin = devm_gpiod_get_optional(
                &pdev->dev, "atmel,vbus_en", GPIOD_OUT_LOW);
        gpiod_set_value(udc->vbus_en_pin, 1);

        udc->id_ctrl_pin = devm_gpiod_get_optional(&pdev->dev, "atmel,id_ctrl", GPIOD_OUT_LOW);
        gpiod_set_value(udc->id_ctrl_pin, 0);

        pp = NULL;
        while ((pp = of_get_next_child(np, pp)))
            udc->num_ep++;

        /* num 16 */
        pr_err("joker %s:in %d.ep num %d\n",__func__,__LINE__, udc->num_ep);

        eps = devm_kzalloc(&pdev->dev, sizeof(struct usba_ep) * udc->num_ep,
                   GFP_KERNEL); <tag4>

        udc->gadget.ep0 = &eps[0].ep; <tag5>

        INIT_LIST_HEAD(&eps[0].ep.ep_list);

        pp = NULL;
        i = 0;
        while ((pp = of_get_next_child(np, pp))) {
            ep = &eps[i];

            ret = of_property_read_u32(pp, "id", &val);

            ep->index = val;

            ret = of_property_read_u32(pp, "atmel,fifo-size", &val); /* ep 的最大包大小 */

            ep->fifo_size = val;

            ret = of_property_read_u32(pp, "atmel,nb-banks", &val);

            ep->nr_banks = val;

            ep->can_dma = of_property_read_bool(pp, "atmel,can-dma"); /* 该ep 能否通过dma传输数据 */
            ep->can_isoc = of_property_read_bool(pp, "atmel,can-isoc"); /* 该ep 能够进行同步传输 */

            ret = of_property_read_string(pp, "name", &name);

            ep->ep.name = name;

            ep->ep_regs = udc->regs + USBA_EPT_BASE(i);
            ep->dma_regs = udc->regs + USBA_DMA_BASE(i);
            ep->fifo = udc->fifo + USBA_FIFO_BASE(i); <tag57>
            ep->ep.ops = &usba_ep_ops;
            usb_ep_set_maxpacket_limit(&ep->ep, ep->fifo_size);
            static inline void usb_ep_set_maxpacket_limit(struct usb_ep *ep,
                                      unsigned maxpacket_limit)
            {
                ep->maxpacket_limit = maxpacket_limit;
                ep->maxpacket = maxpacket_limit;
            }
            ep->udc = udc; <tag6>
            INIT_LIST_HEAD(&ep->queue);

            if (ep->index == 0) {
                pr_err("joker %s:in %d. i %d\n",__func__,__LINE__, i); // 0
                ep->ep.caps.type_control = true; <tag8>
            } else {
                pr_err("joker %s:in %d. i %d\n",__func__,__LINE__, i);// 1~15
                ep->ep.caps.type_iso = ep->can_isoc; <tag7>
                ep->ep.caps.type_bulk = true;
                ep->ep.caps.type_int = true;
            }

            ep->ep.caps.dir_in = true;  /* 所有ep都是双向端点. */
            ep->ep.caps.dir_out = true;

            if (i) {
                pr_err("joker %s:in %d. i %d\n",__func__,__LINE__, i); //1~15
                list_add_tail(&ep->ep.ep_list, &udc->gadget.ep_list); <tag9>
            }

            i++;
        }

        return eps;
    }

	ret = devm_request_irq(&pdev->dev, irq, usba_udc_irq, 0, "atmel_usba_udc", udc);
	
	udc->irq = irq;

	udc->notify_on = true;
	if (udc->vbus_pin) {
		irq_set_status_flags(gpiod_to_irq(udc->vbus_pin),
				IRQ_NOAUTOEN);
		ret = devm_request_threaded_irq(&pdev->dev,
				gpiod_to_irq(udc->vbus_pin), NULL,
				usba_vbus_irq_thread, USBA_VBUS_IRQFLAGS,"atmel_usba_udc", udc);
                static irqreturn_t usba_vbus_irq_thread(int irq, void *devid)
                {
                    struct usba_udc *udc = devid;
                    int vbus;

                    /* debounce */
                    udelay(10);

                    mutex_lock(&udc->vbus_mutex);

                    vbus = vbus_is_present(udc);
                    if (vbus != udc->vbus_prev) {
                        if (vbus) {
                            usba_start(udc);
                            static int usba_start(struct usba_udc *udc)
                            {
                                unsigned long flags;
                                int ret;

                                ret = start_clock(udc);

                                spin_lock_irqsave(&udc->lock, flags);
                                /* 使能控制器, 使能写控制器寄存器功能. */
                                usba_writel(udc, CTRL, USBA_ENABLE_MASK);
                                usba_int_enb_set(udc, USBA_END_OF_RESET);
                                static inline void usba_int_enb_set(struct usba_udc *udc, u32 val)
                                {
                                    usba_writel(udc, INT_ENB, val);
                                    udc->int_enb_cache = val;
                                }
                                spin_unlock_irqrestore(&udc->lock, flags);

                                return 0;
                            }
                        }
                        udc->vbus_prev = vbus;
                    }

                    mutex_unlock(&udc->vbus_mutex);
                    return IRQ_HANDLED;
                }
				
	}

	if (udc->id_pin) {
		udc->id_pin_detect_on = false;
		ret = devm_request_threaded_irq(&pdev->dev,
				gpiod_to_irq(udc->id_pin), NULL,
				usba_id_irq_thread, USBA_ID_IRQFLAGS, "atmel_usba_udc_id", udc);
                static irqreturn_t usba_id_irq_thread(int irq, void *devid)
                {
                    struct usba_udc *udc = devid;
                    int id, vbus;

                    /* debounce */
                    udelay(10);

                    mutex_lock(&udc->vbus_mutex);

                    vbus = vbus_is_present(udc);
                    static int vbus_is_present(struct usba_udc *udc)
                    {
                        if (udc->vbus_pin)
                            return gpiod_get_value(udc->vbus_pin);

                        /* No Vbus detection: Assume always present */
                        return 1;
                    }
                    id = is_usb_host(udc);
                    static bool is_usb_host(struct usba_udc *udc)
                    {
                        if (udc->id_pin_detect_on && gpiod_get_value(udc->id_pin)){
                            return true;
                        }
                        else { //
                            return false;
                        }
                    }

                    mutex_unlock(&udc->vbus_mutex);

                    return IRQ_HANDLED;
                }

		disable_irq(gpiod_to_irq(udc->id_pin));
	}

	ret = usb_add_gadget_udc(&pdev->dev, &udc->gadget);
    int usb_add_gadget_udc(struct device *parent, struct usb_gadget *gadget)
    {
        pr_err("joker %s:in %d.\n",__func__,__LINE__);
        return usb_add_gadget_udc_release(parent, gadget, NULL);
        int usb_add_gadget_udc_release(struct device *parent, struct usb_gadget *gadget,
                void (*release)(struct device *dev))
        {
            struct usb_udc		*udc;
            int			ret = -ENOMEM;

            udc = kzalloc(sizeof(*udc), GFP_KERNEL); <tag10>

            dev_set_name(&gadget->dev, "gadget");
            INIT_WORK(&gadget->work, usb_gadget_state_work);
            gadget->dev.parent = parent;

            dma_set_coherent_mask(&gadget->dev, parent->coherent_dma_mask);
            gadget->dev.dma_parms = parent->dma_parms;
            gadget->dev.dma_mask = parent->dma_mask;

            if (release) {
            }
            else {
                gadget->dev.release = usb_udc_nop_release;
            }

            ret = device_register(&gadget->dev);

            udc->gadget = gadget; <tag11>
            gadget->udc = udc; <tag12>

            mutex_lock(&udc_lock);
            list_add_tail(&udc->list, &udc_list); <tag58>


            udc->vbus = true;

            mutex_unlock(&udc_lock);

            return 0;
        }
    }

	return 0;
}

int usb_composite_probe(struct usb_composite_driver *driver)
{
	struct usb_gadget_driver *gadget_driver;

	driver->gadget_driver = composite_driver_template;
	gadget_driver = &driver->gadget_driver;

	gadget_driver->function =  (char *) driver->name;
	gadget_driver->driver.name = driver->name;
	gadget_driver->max_speed = driver->max_speed;

	return usb_gadget_probe_driver(gadget_driver);
    int usb_gadget_probe_driver(struct usb_gadget_driver *driver)
    {
        struct usb_udc		*udc = NULL;
        int			ret;

        mutex_lock(&udc_lock);
        list_for_each_entry(udc, &udc_list, list) { /* 循环一次而已 */
            /* For now we take the first one */
            if (!udc->driver) {
                goto found;
            }
        }

    found:
        ret = udc_bind_to_driver(udc, driver);
        static int udc_bind_to_driver(struct usb_udc *udc, struct usb_gadget_driver *driver)
        {
            int ret;

            udc->driver = driver;
            udc->dev.driver = &driver->driver;
            udc->gadget->dev.driver = &driver->driver;

            /* composite_bind */
            ret = driver->bind(udc->gadget, driver);
            static int composite_bind(struct usb_gadget *gadget, struct usb_gadget_driver *gdriver)
            {
                struct usb_composite_dev	*cdev;
                struct usb_composite_driver	*composite = to_cdriver(gdriver);
                int				status = -ENOMEM;

                cdev = kzalloc(sizeof *cdev, GFP_KERNEL); <tag13>

                spin_lock_init(&cdev->lock);
                cdev->gadget = gadget; <tag14>
                set_gadget_data(gadget, cdev); <tag15>
                static inline void set_gadget_data(struct usb_gadget *gadget, void *data)
                {
                    dev_set_drvdata(&gadget->dev, data);
                    static inline void dev_set_drvdata(struct device *dev, void *data)
                    {
                        dev->driver_data = data;
                    }
                }
                INIT_LIST_HEAD(&cdev->configs);
                INIT_LIST_HEAD(&cdev->gstrings);

                status = composite_dev_prepare(composite, cdev);
                int composite_dev_prepare(struct usb_composite_driver *composite,
                        struct usb_composite_dev *cdev)
                {
                    struct usb_gadget *gadget = cdev->gadget;
                    int ret = -ENOMEM;

                    /* preallocate control response and buffer */
                    cdev->req = usb_ep_alloc_request(gadget->ep0, GFP_KERNEL); <tag16>
                    static inline struct usb_request *usb_ep_alloc_request(struct usb_ep *ep, gfp_t gfp_flags)
                    {
                        /* usba_ep_alloc_request */
                        return ep->ops->alloc_request(ep, gfp_flags);
                        static struct usb_request *
                        usba_ep_alloc_request(struct usb_ep *_ep, gfp_t gfp_flags)
                        {
                            struct usba_request *req;

                            req = kzalloc(sizeof(*req), gfp_flags); <tag37>

                            INIT_LIST_HEAD(&req->queue);

                            return &req->req;
                        }
                    }

                    cdev->req->buf = kmalloc(USB_COMP_EP0_BUFSIZ, GFP_KERNEL); <tag17>

                    ret = device_create_file(&gadget->dev, &dev_attr_suspended);

                    cdev->req->complete = composite_setup_complete;
                    cdev->req->context = cdev; <tag18>
                    gadget->ep0->driver_data = cdev;

                    cdev->driver = composite;

                    /*
                     * As per USB compliance update, a device that is actively drawing
                     * more than 100mA from USB must report itself as bus-powered in
                     * the GetStatus(DEVICE) call.
                     */
                    if (CONFIG_USB_GADGET_VBUS_DRAW <= USB_SELF_POWER_VBUS_MAX_DRAW) {
                        //usb_gadget_set_selfpowered(gadget);
                    }

                    /* interface and string IDs start at zero via kzalloc.
                     * we force endpoints to start unassigned; few controller
                     * drivers will zero ep->driver_data.
                     */
                    //usb_ep_autoconfig_reset(gadget);
                    return 0;
                }

                /* composite gadget needs to assign strings for whole device (like
                 * serial number), register function drivers, potentially update
                 * power state and consumption, etc
                 */
                /* gm_zero_bind */
                status = composite->bind(cdev);
                static int gm_zero_bind(struct usb_composite_dev *cdev)
                {
                    int			status;

                    func_lb = loopback_alloc(); <tag24>
                    static struct usb_function *loopback_alloc(void)
                    {
                        struct f_loopback	*loop;

                        loop = kzalloc(sizeof *loop, GFP_KERNEL); <tag21>

                        loop->buflen = gzero_options.bulk_buflen;

                        loop->function.bind = loopback_bind;
                        loop->function.set_alt = loopback_set_alt;
                        loop->function.disable = loopback_disable;

                        loop->function.free_func = lb_free_func;

                        return &loop->function;
                    }

                    /* Register primary, then secondary configuration.  Note that
                     * SH3 only allows one config...
                     */
                    /* loopback_driver 包含usb设备的配置描述符信息,
                     * usb_add_function() 将 描述符信息集合至 cdev*/
                    usb_add_config_only(cdev, &loopback_driver);
                    int usb_add_config_only(struct usb_composite_dev *cdev,
                            struct usb_configuration *config)
                    {
                        struct usb_configuration *c;

                        config->cdev = cdev; <tag22>
                        list_add_tail(&config->list, &cdev->configs); <tag23>

                        INIT_LIST_HEAD(&config->functions);
                        config->next_interface_id = 0;
                        memset(config->interface, 0, sizeof(config->interface));

                        return 0;
                    }

                    /* func_lb 包含 接口描述符和端点描述符信息,
                     * usb_add_function() 将 信息集合至 loopback_driver*/
                    status = usb_add_function(&loopback_driver, func_lb);
                    int usb_add_function(struct usb_configuration *config,
                            struct usb_function *function)
                    {
                        int	value = -EINVAL;

                        function->config = config; <tag25>
                        list_add_tail(&function->list, &config->functions); <tag26>

                        /* REVISIT *require* function->bind? */
                        if (function->bind) {
                            /* loopback_bind */
                            value = function->bind(config, function);
                            static int loopback_bind(struct usb_configuration *c, struct usb_function *f)
                            {
                                struct usb_composite_dev *cdev = c->cdev;
                                struct f_loopback	*loop = func_to_loop(f);
                                int			id;
                                int ret;

                                /* allocate interface ID(s) */
                                id = usb_interface_id(c, f);
                                int usb_interface_id(struct usb_configuration *config,
                                        struct usb_function *function)
                                {
                                    unsigned id = config->next_interface_id;

                                    /* id==0 */
                                    if (id < MAX_CONFIG_INTERFACES) {
                                        config->interface[id] = function; <tag27>
                                        config->next_interface_id = id + 1;
                                        return id;
                                    }
                                }
                                loopback_intf.bInterfaceNumber = id;

                                /* usb_ep_autoconfig() 根据端点描述符信息, 从ep列表里,
                                 * 找到匹配的合适的ep, 将其返回.*/
                                loop->in_ep = usb_ep_autoconfig(cdev->gadget, &hs_loop_source_desc); <tag28>
                                struct usb_ep *usb_ep_autoconfig(
                                    struct usb_gadget		*gadget,
                                    struct usb_endpoint_descriptor	*desc)
                                {
                                    return usb_ep_autoconfig_ss(gadget, desc, NULL);
                                    struct usb_ep *usb_ep_autoconfig_ss(
                                        struct usb_gadget		*gadget,
                                        struct usb_endpoint_descriptor	*desc,
                                        struct usb_ss_ep_comp_descriptor *ep_comp
                                    )
                                    {
                                        struct usb_ep	*ep;
                                        u8		type;

                                        type = desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK;

                                        /* Second, look at endpoints until an unclaimed one looks usable */
                                        list_for_each_entry (ep, &gadget->ep_list, ep_list) {
                                            if (usb_gadget_ep_match_desc(gadget, ep, desc, ep_comp)) {
                                                goto found_ep;
                                                int usb_gadget_ep_match_desc(struct usb_gadget *gadget,
                                                        struct usb_ep *ep, struct usb_endpoint_descriptor *desc,
                                                        struct usb_ss_ep_comp_descriptor *ep_comp)
                                                {
                                                    u8		type;
                                                    u16		max;
                                                    int		num_req_streams = 0;

                                                    /* endpoint already claimed? */
                                                    if (ep->claimed) {
                                                        return 0;
                                                    }

                                                    return 1;
                                                }
                                            }
                                        }

                                        /* Fail */
                                        return NULL;
                                    found_ep:

                                        /* report address */
                                        desc->bEndpointAddress &= USB_DIR_IN;
                                        if (isdigit(ep->name[2])) {
                                            u8 num = simple_strtoul(&ep->name[2], NULL, 10);
                                            desc->bEndpointAddress |= num;
                                        }

                                        /* report (variable) full speed bulk maxpacket */
                                        if ((type == USB_ENDPOINT_XFER_BULK) && !ep_comp) {
                                            int size = ep->maxpacket_limit;

                                            /* min() doesn't work on bitfields with gcc-3.5 */
                                            if (size > 64) {//
                                                size = 64;
                                            }
                                            desc->wMaxPacketSize = cpu_to_le16(size);
                                        }

                                        ep->address = desc->bEndpointAddress;
                                        ep->desc = NULL;
                                        ep->comp_desc = NULL;
                                        ep->claimed = true;
                                        pr_err("joker %s:in %d.\n",__func__,__LINE__);
                                        return ep;
                                    }
                                }

                                loop->out_ep = usb_ep_autoconfig(cdev->gadget, &hs_loop_sink_desc); <tag29>

                                /* usb_assign_descriptors() 将接口描述符和端点描述符信息, 
                                 * 集合至 f, 即func_lb.*/
                                ret = usb_assign_descriptors(f, NULL, hs_loopback_descs, NULL);
                                int usb_assign_descriptors(struct usb_function *f,
                                        struct usb_descriptor_header **fs,
                                        struct usb_descriptor_header **hs,
                                        struct usb_descriptor_header **ss)
                                {
                                    struct usb_gadget *g = f->config->cdev->gadget;

                                    if (hs && gadget_is_dualspeed(g))
                                    {
                                        f->hs_descriptors = usb_copy_descriptors(hs); <tag30>
                                        struct usb_descriptor_header **usb_copy_descriptors(struct usb_descriptor_header **src)
                                        {
                                            struct usb_descriptor_header **tmp;
                                            unsigned bytes;
                                            unsigned n_desc;
                                            void *mem;
                                            struct usb_descriptor_header **ret;

                                            /* count descriptors and their sizes; then add vector size */
                                            for (bytes = 0, n_desc = 0, tmp = src; *tmp; tmp++, n_desc++)
                                                bytes += (*tmp)->bLength;
                                            bytes += (n_desc + 1) * sizeof(*tmp);

                                            mem = kmalloc(bytes, GFP_KERNEL);

                                            /* fill in pointers starting at "tmp",
                                             * to descriptors copied starting at "mem";
                                             * and return "ret"
                                             */
                                            tmp = mem;
                                            ret = mem;
                                            mem += (n_desc + 1) * sizeof(*tmp);
                                            while (*src) {
                                                memcpy(mem, *src, (*src)->bLength);
                                                *tmp = mem;
                                                tmp++;
                                                mem += (*src)->bLength;
                                                src++;
                                            }
                                            *tmp = NULL;

                                            return ret;
                                        }
                                    }

                                    return 0;
                                }
                                return 0;
                            }
                        }

                        if (!config->highspeed && function->hs_descriptors) {
                            config->highspeed = true;
                        }

                        return value;
                    }

                    return 0;
                }

                update_unchanged_dev_desc(&cdev->desc, composite->dev);
                static void update_unchanged_dev_desc(struct usb_device_descriptor *new,
                        const struct usb_device_descriptor *old)
                {
                    __le16 idVendor;
                    __le16 idProduct;
                    __le16 bcdDevice;
                    u8 iSerialNumber;
                    u8 iManufacturer;
                    u8 iProduct;

                    /*
                     * these variables may have been set in
                     * usb_composite_overwrite_options()
                     */
                    idVendor = new->idVendor;
                    idProduct = new->idProduct;
                    bcdDevice = new->bcdDevice;
                    iSerialNumber = new->iSerialNumber;
                    iManufacturer = new->iManufacturer;
                    iProduct = new->iProduct;

                    *new = *old;

                    if (bcdDevice) {
                    }
                    else {
                        new->bcdDevice = cpu_to_le16(get_default_bcdDevice());
                    }
                }

                return 0;
            }
            ret = usb_gadget_udc_start(udc);
            static inline int usb_gadget_udc_start(struct usb_udc *udc)
            {
                /* atmel_usba_start */
                return udc->gadget->ops->udc_start(udc->gadget, udc->driver);
                static int atmel_usba_start(struct usb_gadget *gadget,
                        struct usb_gadget_driver *driver)
                {
                    int ret;
                    struct usba_udc *udc = container_of(gadget, struct usba_udc, gadget);
                    unsigned long flags;

                    spin_lock_irqsave(&udc->lock, flags);
                    udc->devstatus = 1 << USB_DEVICE_SELF_POWERED;
                    udc->driver = driver;
                    spin_unlock_irqrestore(&udc->lock, flags);

                    mutex_lock(&udc->vbus_mutex);

                    /*
                    if (udc->vbus_pin) {//
                        enable_vbus_detect(udc, true);
                    }
                    */

                    /* If Vbus is present, enable the controller and wait for reset */
                    udc->vbus_prev = vbus_is_present(udc);
                    if (udc->vbus_prev) {//
                        ret = usba_start(udc);
                        static int usba_start(struct usba_udc *udc)
                        {
                            unsigned long flags;
                            int ret;

                            ret = start_clock(udc);
                            static int start_clock(struct usba_udc *udc)
                            {
                                int ret;

                                ret = clk_prepare_enable(udc->pclk);
                                ret = clk_prepare_enable(udc->hclk);

                                udc->clocked = true;
                                return 0;
                            }

                            spin_lock_irqsave(&udc->lock, flags);
                            usba_writel(udc, CTRL, USBA_ENABLE_MASK);
                            usba_int_enb_set(udc, USBA_END_OF_RESET);
                            static inline void usba_int_enb_set(struct usba_udc *udc, u32 val)
                            {
                                usba_writel(udc, INT_ENB, val);
                                udc->int_enb_cache = val;
                            }
                            spin_unlock_irqrestore(&udc->lock, flags);

                            return 0;
                        }
                    }

                    mutex_unlock(&udc->vbus_mutex);
                    return 0;
                }
            }

            return 0;
        }
        mutex_unlock(&udc_lock);
        return ret;
    }
}

static irqreturn_t usba_udc_irq(int irq, void *devid)
{
	struct usba_udc *udc = devid;
	u32 status, int_enb;
	u32 dma_status;
	u32 ep_status;

	spin_lock(&udc->lock);

	int_enb = usba_int_enb_get(udc);
    static inline u32 usba_int_enb_get(struct usba_udc *udc)
    {
        return udc->int_enb_cache;
    }
	status = usba_readl(udc, INT_STA) & (int_enb | USBA_HIGH_SPEED);
	DBG(DBG_INT, "irq, status=%#08x\n", status);

	if (status & USBA_DET_SUSPEND) { //
		//toggle_bias(udc, 0);
        /* 写1, 清除INT_STA寄存器的中断标志位 */
		usba_writel(udc, INT_CLR, USBA_DET_SUSPEND);
		//usba_int_enb_set(udc, int_enb | USBA_WAKE_UP);
		udc->bias_pulse_needed = true;
		if (udc->gadget.speed != USB_SPEED_UNKNOWN
				&& udc->driver && udc->driver->suspend) { //
			spin_unlock(&udc->lock);
            /* composite_suspend */
			udc->driver->suspend(&udc->gadget);
            void composite_suspend(struct usb_gadget *gadget)
            {
                struct usb_composite_dev	*cdev = get_gadget_data(gadget);
                struct usb_function		*f;

                cdev->suspended = 1;

                usb_gadget_vbus_draw(gadget, 2);
            }
			spin_lock(&udc->lock);
		}
	}

	dma_status = USBA_BFEXT(DMA_INT, status);
    #define USBA_BFEXT(name, value)					\
        (((value) >> USBA_##name##_OFFSET)			\
         & ((1 << USBA_##name##_SIZE) - 1))
	if (dma_status) {
		int i;

		for (i = 1; i <= USBA_NR_DMAS; i++)
			if (dma_status & (1 << i)) {//
				usba_dma_irq(udc, &udc->usba_ep[i]);
                static void usba_dma_irq(struct usba_udc *udc, struct usba_ep *ep)
                {
                    struct usba_request *req;
                    u32 status, control, pending;

                    status = usba_dma_readl(ep, STATUS);
                    control = usba_dma_readl(ep, CONTROL);

                    pending = status & control;

                    /*
                    if (list_empty(&ep->queue)) {
                        return;
                    }*/

                    /* dma buf 传输完成 */
                    if (pending & (USBA_DMA_END_TR_ST | USBA_DMA_END_BUF_ST)) {//
                        req = list_entry(ep->queue.next, struct usba_request, queue);
                        usba_update_req(ep, req, status);
                        static void usba_update_req(struct usba_ep *ep, struct usba_request *req, u32 status)
                        {
                            req->req.actual = req->req.length - USBA_BFEXT(DMA_BUF_LEN, status);
                        }

                        list_del_init(&req->queue);
                        request_complete(ep, req, 0);
                        static void request_complete(struct usba_ep *ep, struct usba_request *req, int status)
                        {
                            struct usba_udc *udc = ep->udc;

                            if (req->req.status == -EINPROGRESS) { //
                                req->req.status = status;
                            }

                            if (req->using_dma) { //
                            }

                            DBG(DBG_GADGET | DBG_REQ,
                                "%s: req %p complete: status %d, actual %u\n",
                                ep->ep.name, req, req->req.status, req->req.actual);

                            spin_unlock(&udc->lock);
                            usb_gadget_giveback_request(&ep->ep, &req->req);
                            void usb_gadget_giveback_request(struct usb_ep *ep,
                                    struct usb_request *req)
                            {
                                /*
                                if (likely(req->status == 0)) { //
                                    usb_led_activity(USB_LED_EVENT_GADGET);
                                }*/

                                /* loopback_complete */
                                req->complete(ep, req);
                                ================== 1================
                                static void loopback_complete(struct usb_ep *ep, struct usb_request *req) 
                                {
                                    struct f_loopback	*loop = ep->driver_data;
                                    struct usb_composite_dev *cdev = loop->function.config->cdev;
                                    int			status = req->status;

                                    switch (status) {
                                    case 0:				/* normal completion? */
                                        if (ep == loop->out_ep) {
                                            /*
                                             * We received some data from the host so let's
                                             * queue it so host can read the from our in ep
                                             */
                                            struct usb_request *in_req = req->context;

                                            in_req->zero = (req->actual < req->length);
                                            in_req->length = req->actual;
                                            ep = loop->in_ep;
                                            req = in_req;
                                        }

                                        /* queue the buffer back to host or for next bunch of data */
                                        status = usb_ep_queue(ep, req, GFP_ATOMIC);
                                        static inline int usb_ep_queue(struct usb_ep *ep,
                                                           struct usb_request *req, gfp_t gfp_flags)
                                        {
                                            /* usba_ep_queue */
                                            return ep->ops->queue(ep, req, gfp_flags);
                                            static int
                                            usba_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
                                            {
                                                struct usba_request *req = to_usba_req(_req);
                                                struct usba_ep *ep = to_usba_ep(_ep);
                                                struct usba_udc *udc = ep->udc;
                                                unsigned long flags;
                                                int ret;

                                                req->submitted = 0;
                                                req->using_dma = 0;
                                                req->last_transaction = 0;

                                                _req->status = -EINPROGRESS;
                                                _req->actual = 0;

                                                if (ep->can_dma) { //
                                                    return queue_dma(udc, ep, req, gfp_flags);
                                                    static int queue_dma(struct usba_udc *udc,
                                                            struct usba_ep *ep,struct usba_request *req, gfp_t gfp_flags)
                                                    {
                                                        unsigned long flags;
                                                        int ret;

                                                        DBG(DBG_DMA, "%s: req l/%u d/%pad %c%c%c\n",
                                                            ep->ep.name, req->req.length, &req->req.dma,
                                                            req->req.zero ? 'Z' : 'z',
                                                            req->req.short_not_ok ? 'S' : 's',
                                                            req->req.no_interrupt ? 'I' : 'i');

                                                        ret = usb_gadget_map_request(&udc->gadget,
                                                                            &req->req, ep->is_in);
                                                        int usb_gadget_map_request(
                                                                struct usb_gadget *gadget,
                                                                struct usb_request *req, int is_in)
                                                        {
                                                            struct device *dev = gadget->dev.parent;

                                                            if (req->num_sgs) {
                                                            } else { 
                                                                req->dma = dma_map_single(dev,
                                                                        req->buf, req->length,
                                                                        is_in ? DMA_TO_DEVICE
                                                                                        : DMA_FROM_DEVICE);
                                                            }

                                                            return 0;
                                                        }

                                                        req->using_dma = 1;
                                                        req->ctrl = USBA_BF(DMA_BUF_LEN, req->req.length)
                                                                | USBA_DMA_CH_EN | USBA_DMA_END_BUF_IE
                                                                | USBA_DMA_END_BUF_EN;

                                                        if (!ep->is_in) { //in_ep
                                                            req->ctrl |= USBA_DMA_END_TR_EN
                                                                            | USBA_DMA_END_TR_IE;
                                                        }

                                                        /*
                                                         * Add this request to the queue and submit for DMA if
                                                         * possible. Check if we're still alive first -- we may have
                                                         * received a reset since last time we checked.
                                                         */
                                                        ret = -ESHUTDOWN;
                                                        spin_lock_irqsave(&udc->lock, flags);
                                                        if (ep->ep.desc) {
                                                            if (list_empty(&ep->queue)) { //
                                                                submit_request(ep, req);
                                                                static void submit_request(struct usba_ep *ep, struct usba_request *req)
                                                                {
                                                                    req->req.actual = 0;
                                                                    req->submitted = 1;

                                                                    if (req->using_dma) {
                                                                        if (req->req.zero) { 
                                                                            usba_ep_writel(ep, CTL_ENB, USBA_SHORT_PACKET);
                                                                        }

                                                                        usba_dma_writel(ep, ADDRESS, req->req.dma);
                                                                        usba_dma_writel(ep, CONTROL, req->ctrl);
                                                                    }
                                                                }
                                                            }

                                                            list_add_tail(&req->queue, &ep->queue);
                                                            ret = 0;
                                                        }
                                                        spin_unlock_irqrestore(&udc->lock, flags);

                                                        return ret;
                                                    }
                                                }
                                            }
                                        }
                                        if (status == 0) {
                                            return;
                                        }
                                    }
                                }
                                ========================2===============
                                static void loopback_complete(struct usb_ep *ep, struct usb_request *req)
                                {
                                    pr_err("joker %s:in %d.\n",__func__,__LINE__);
                                    struct f_loopback	*loop = ep->driver_data;
                                    struct usb_composite_dev *cdev = loop->function.config->cdev;
                                    int			status = req->status;

                                    switch (status) {
                                    case 0:				/* normal completion? */
                                        if (ep == loop->out_ep) {

                                        } else {
                                            /*
                                             * We have just looped back a bunch of data
                                             * to host. Now let's wait for some more data.
                                             */
                                            req = req->context;
                                            ep = loop->out_ep;
                                        }

                                        /* queue the buffer back to host or for next bunch of data */
                                        status = usb_ep_queue(ep, req, GFP_ATOMIC);
                                        static inline int usb_ep_queue(struct usb_ep *ep,
                                                           struct usb_request *req, gfp_t gfp_flags)
                                        {
                                            /* usba_ep_queue */
                                            return ep->ops->queue(ep, req, gfp_flags);
                                            static int
                                            usba_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
                                            {
                                                struct usba_request *req = to_usba_req(_req);
                                                struct usba_ep *ep = to_usba_ep(_ep);
                                                struct usba_udc *udc = ep->udc;
                                                unsigned long flags;
                                                int ret;

                                                req->submitted = 0;
                                                req->using_dma = 0;
                                                req->last_transaction = 0;

                                                _req->status = -EINPROGRESS;
                                                _req->actual = 0;

                                                if (ep->can_dma) { //
                                                    return queue_dma(udc, ep, req, gfp_flags);
                                                    static int queue_dma(struct usba_udc *udc,
                                                            struct usba_ep *ep,struct usba_request *req, gfp_t gfp_flags)
                                                    {
                                                        unsigned long flags;
                                                        int ret;

                                                        DBG(DBG_DMA, "%s: req l/%u d/%pad %c%c%c\n",
                                                            ep->ep.name, req->req.length, &req->req.dma,
                                                            req->req.zero ? 'Z' : 'z',
                                                            req->req.short_not_ok ? 'S' : 's',
                                                            req->req.no_interrupt ? 'I' : 'i');

                                                        ret = usb_gadget_map_request(&udc->gadget,
                                                                            &req->req, ep->is_in);
                                                        int usb_gadget_map_request(
                                                                struct usb_gadget *gadget,
                                                                struct usb_request *req, int is_in)
                                                        {
                                                            struct device *dev = gadget->dev.parent;

                                                            if (req->num_sgs) {
                                                            } else { 
                                                                req->dma = dma_map_single(dev,
                                                                        req->buf, req->length,
                                                                        is_in ? DMA_TO_DEVICE
                                                                                        : DMA_FROM_DEVICE);
                                                            }

                                                            return 0;
                                                        }

                                                        req->using_dma = 1;
                                                        req->ctrl = USBA_BF(DMA_BUF_LEN, req->req.length)
                                                                | USBA_DMA_CH_EN | USBA_DMA_END_BUF_IE
                                                                | USBA_DMA_END_BUF_EN;

                                                        if (!ep->is_in) { //in_ep
                                                            req->ctrl |= USBA_DMA_END_TR_EN
                                                                            | USBA_DMA_END_TR_IE;
                                                        }

                                                        /*
                                                         * Add this request to the queue and submit for DMA if
                                                         * possible. Check if we're still alive first -- we may have
                                                         * received a reset since last time we checked.
                                                         */
                                                        ret = -ESHUTDOWN;
                                                        spin_lock_irqsave(&udc->lock, flags);
                                                        if (ep->ep.desc) {
                                                            if (list_empty(&ep->queue)) { //
                                                                submit_request(ep, req);
                                                                static void submit_request(struct usba_ep *ep, struct usba_request *req)
                                                                {
                                                                    req->req.actual = 0;
                                                                    req->submitted = 1;

                                                                    if (req->using_dma) { //
                                                                        if (req->req.zero) {
                                                                        }
                                                                        else { //
                                                                            usba_ep_writel(ep, CTL_DIS, USBA_SHORT_PACKET);
                                                                        }

                                                                        usba_dma_writel(ep, ADDRESS, req->req.dma);
                                                                        usba_dma_writel(ep, CONTROL, req->ctrl);
                                                                    }
                                                                }

                                                            }

                                                            list_add_tail(&req->queue, &ep->queue);
                                                            ret = 0;
                                                        }
                                                        spin_unlock_irqrestore(&udc->lock, flags);

                                                        return ret;
                                                    }
                                                }
                                            }
                                        }
                                        if (status == 0) {
                                            return;
                                        }
                                    }
                                }
                                ============== end loopback_complete===============
                            }
                            spin_lock(&udc->lock);
                        }
                    }
                }
            }
	}

	ep_status = USBA_BFEXT(EPT_INT, status);
    /* 取 UDPHS_INTSTA 寄存器 8~23 位, ep0~15 的中断标志位 */
    #define USBA_BFEXT(name, value)		  (value >> 8) & ((1<<16)-1)
        (((value) >> USBA_EPT_INT_OFFSET)	& ((1 << USBA_EPT_INT_SIZE) - 1))
	if (ep_status) { // 全都是处理 ep0, 其他被使用的ep使用dma进行传输, 不进入此判断..
		int i;

		for (i = 0; i < udc->num_ep; i++)
			if (ep_status & (1 << i)) {
				if (ep_is_control(&udc->usba_ep[i])) { //
                    switch (ep0_use_count) {
                        case 0:
        					case0_usba_control_irq(udc, &udc->usba_ep[i]);
                            static void case0_usba_control_irq(struct usba_udc *udc, struct usba_ep *ep)
                            {
                                struct usba_request *req;
                                u32 epstatus;
                                u32 epctrl;

                                /* 获取端点状态寄存器的值. */
                                epstatus = usba_ep_readl(ep, STA);
                                /* 获取端点控制寄存器的值 */
                                epctrl = usba_ep_readl(ep, CTL);

                                req = NULL;

                                /* 当收到 setup 包时, 置位RX_SETUP. */
                                if (epstatus & USBA_RX_SETUP) {
                                    union {
                                        struct usb_ctrlrequest crq;
                                        unsigned long data[2];
                                    } crq;
                                    unsigned int pkt_len;
                                    int ret;

                                    pkt_len = USBA_BFEXT(BYTE_COUNT, usba_ep_readl(ep, STA));
                                    #define USBA_BFEXT(name, value)	 (value >> 20) & ((1<<11)-1)
                                        	(((value) >> USBA_BYTE_COUNT_OFFSET) & ((1 << USBA_BYTE_COUNT_SIZE) - 1))

                                    /* host 请求 设备描述符 */
                                    /* bRequestType 0x80. bRequest 0x06, wValue 0x100length 64 */
                                    /* 将ep 接收到的数据 复制 到 crq.data. */
                                    memcpy_fromio(crq.data, ep->fifo, sizeof(crq));

                                    /* Free up one bank in the FIFO so that we can
                                     * generate or receive a reply right away. */
                                    /* Clear the RX_SETUP flags of UDPHS_EPTSTAx */
                                    /* 清除 UDPHS_EPTSTAx 寄存器中的 RX_SETUP 标志位 */
                                    usba_ep_writel(ep, CLR_STA, USBA_RX_SETUP);

                                    if (crq.crq.bRequestType & USB_DIR_IN) { //
                                        /*
                                         * The USB 2.0 spec states that "if wLength is
                                         * zero, there is no data transfer phase."
                                         * However, testusb #14 seems to actually
                                         * expect a data phase even if wLength = 0...
                                         */
                                        ep->state = DATA_STAGE_IN;
                                    }

                                    ret = -1;
                                    if (ep->index == 0) { //
                                        ret = case0_handle_ep0_setup(udc, ep, &crq.crq);
                                        //handle_ep0_setup(udc, ep, &crq.crq);
                                        static int case0_handle_ep0_setup(struct usba_udc *udc, struct usba_ep *ep,
                                                struct usb_ctrlrequest *crq)
                                        {
                                            int retval = 0;

                                            switch (crq->bRequest) {
                                            default:
                                                spin_unlock(&udc->lock);
                                                /* composite_setup */
                                                retval = udc->driver->setup(&udc->gadget, crq);
                                                int composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
                                                {
                                                    struct usb_composite_dev	*cdev = get_gadget_data(gadget);
                                                    struct usb_request		*req = cdev->req;
                                                    int				value = -EOPNOTSUPP;
                                                    int				status = 0;
                                                    u16				w_index = le16_to_cpu(ctrl->wIndex);
                                                    u8				intf = w_index & 0xFF;
                                                    u16				w_value = le16_to_cpu(ctrl->wValue);
                                                    u16				w_length = le16_to_cpu(ctrl->wLength);
                                                    struct usb_function		*f = NULL;
                                                    u8				endp;

                                                    /* partial re-init of the response message; the function or the
                                                     * gadget might need to intercept e.g. a control-OUT completion
                                                     * when we delegate to it.
                                                     */
                                                    req->zero = 0;
                                                    req->context = cdev;
                                                    req->complete = composite_setup_complete;
                                                    req->length = 0;
                                                    gadget->ep0->driver_data = cdev;

                                                    switch (ctrl->bRequest) {

                                                    /* we handle all standard USB descriptors */
                                                    case USB_REQ_GET_DESCRIPTOR: 
                                                        switch (w_value >> 8) {

                                                        case USB_DT_DEVICE: 
                                                            cdev->desc.bNumConfigurations = count_configs(cdev, USB_DT_DEVICE);
                                                            static int count_configs(struct usb_composite_dev *cdev, unsigned type)
                                                            {
                                                                struct usb_gadget		*gadget = cdev->gadget;
                                                                struct usb_configuration	*c;
                                                                unsigned			count = 0;
                                                                int				hs = 0;
                                                                int				ss = 0;

                                                                if (gadget_is_dualspeed(gadget)) {
                                                                    if (gadget->speed == USB_SPEED_HIGH) {
                                                                        hs = 1;
                                                                    }
                                                                }
                                                                list_for_each_entry(c, &cdev->configs, list) {
                                                                    /* ignore configs that won't work at this speed */
                                                                    if (hs) {
                                                                    }
                                                                    count++;
                                                                }
                                                                return count;
                                                            }
                                                            cdev->desc.bMaxPacketSize0 = cdev->gadget->ep0->maxpacket; <tag35>
                                                            if (gadget_is_superspeed(gadget)) {
                                                            } else {
                                                                cdev->desc.bcdUSB = cpu_to_le16(0x0200);
                                                            }

                                                            value = min(w_length, (u16) sizeof cdev->desc);
                                                            memcpy(req->buf, &cdev->desc, value); <tag36>
                                                            break;
                                                        }
                                                        break;
                                                    }

                                                    /* respond with data transfer before status phase? */
                                                    /* value >0 表明有数据需要传输. */
                                                    if (value >= 0 && value != USB_GADGET_DELAYED_STATUS) {
                                                        req->length = value;
                                                        req->context = cdev;
                                                        /* 将要传输的数据量 小于请求的数据, device需要发送0长包表示数据发生完毕 */
                                                        req->zero = value < w_length;
                                                        value = composite_ep0_queue(cdev, req, GFP_ATOMIC);
                                                        static int composite_ep0_queue(struct usb_composite_dev *cdev,
                                                                struct usb_request *req, gfp_t gfp_flags)
                                                        {
                                                            int ret;

                                                            ret = usb_ep_queue(cdev->gadget->ep0, req, gfp_flags);
                                                            static inline int usb_ep_queue(struct usb_ep *ep,
                                                                               struct usb_request *req, gfp_t gfp_flags)
                                                            {
                                                                /* usba_ep_queue */
                                                                return ep->ops->queue(ep, req, gfp_flags);
                                                                static int usba_ep_queue(struct usb_ep *_ep,
                                                                            struct usb_request *_req, gfp_t gfp_flags)
                                                                {
                                                                    struct usba_request *req = to_usba_req(_req);
                                                                    struct usba_ep *ep = to_usba_ep(_ep);
                                                                    struct usba_udc *udc = ep->udc;
                                                                    unsigned long flags;
                                                                    int ret;

                                                                    req->submitted = 0;
                                                                    req->using_dma = 0;
                                                                    req->last_transaction = 0;

                                                                    _req->status = -EINPROGRESS;
                                                                    _req->actual = 0;

                                                                    /* May have received a reset since last time we checked */
                                                                    ret = -ESHUTDOWN;
                                                                    spin_lock_irqsave(&udc->lock, flags);
                                                                    if (ep->ep.desc) { //
                                                                        list_add_tail(&req->queue, &ep->queue); <tag38>

                                                                        if ((!ep_is_control(ep) && ep->is_in) ||
                                                                            (ep_is_control(ep)
                                                                                && (ep->state == DATA_STAGE_IN
                                                                                    || ep->state == STATUS_STAGE_IN))) {
                                                                            /* Enable TX Packet Ready/Transaction Error Interrup.*/
                                                                            /* 使能tx包准备ok,和tx传输错误中断. */
                                                                            usba_ep_writel(ep, CTL_ENB, USBA_TX_PK_RDY);
                                                                        }
                                                                        ret = 0;
                                                                    }
                                                                    spin_unlock_irqrestore(&udc->lock, flags);

                                                                    return ret;
                                                                }
                                                            }
                                                            if (ret == 0) {
                                                                if (cdev->req == req) {
                                                                    cdev->setup_pending = true;
                                                                }
                                                            }

                                                            return ret;
                                                        }
                                                    }

                                                    /* device either stalls (value < 0) or reports success */
                                                    return value;
                                                }
                                                spin_lock(&udc->lock);
                                            }

                                            return retval;
                                        }
                                    }
                                }
                            }
                            break;
                        case 1:
        					case1_usba_control_irq(udc, &udc->usba_ep[i]);
        					//usba_control_irq(udc, &udc->usba_ep[i]);
                            static void case1_usba_control_irq(struct usba_udc *udc, struct usba_ep *ep)
                            {
                                struct usba_request *req;
                                u32 epstatus;
                                u32 epctrl;

                                /* 获取端点状态寄存器的值. */
                                epstatus = usba_ep_readl(ep, STA);
                                /* 获取端点控制寄存器的值 */
                                epctrl = usba_ep_readl(ep, CTL);

                                req = NULL;
                                if (!list_empty(&ep->queue)) {
                                    req = list_entry(ep->queue.next, struct usba_request, queue);
                                }

                                /* epctrl & USBA_TX_PK_RDY 值为1, 表示tx包准备ok时将产生中断. */
                                if ((epctrl & USBA_TX_PK_RDY) && !(epstatus & USBA_TX_PK_RDY)) {
                                    if (req->submitted) {
                                    }
                                    else {
                                        submit_request(ep, req);
                                        case1_submit_request(ep, req);
                                        static void case1_submit_request(struct usba_ep *ep, struct usba_request *req)
                                        {
                                            req->req.actual = 0;
                                            req->submitted = 1;

                                            if (req->using_dma) {

                                            } else {
                                                next_fifo_transaction(ep, req);
                                                static void next_fifo_transaction(struct usba_ep *ep, struct usba_request *req)
                                                {
                                                    unsigned int transaction_len;

                                                    transaction_len = req->req.length - req->req.actual;
                                                    req->last_transaction = 1;

                                                    memcpy_toio(ep->fifo, req->req.buf + req->req.actual, transaction_len); <tag39>
                                                    /* 表示ep->fifo已经写入数据, 可以进行数据传输. */
                                                    usba_ep_writel(ep, SET_STA, USBA_TX_PK_RDY);
                                                    req->req.actual += transaction_len;
                                                }
                                                if (req->last_transaction) {
                                                    //USBA_EPT_CTL_DIS
                                                    /* 关闭tx包准备OK, 和tx传输错误中断 */
                                                    usba_ep_writel(ep, CTL_DIS, USBA_TX_PK_RDY);
                                                    /* 使能 IN data 传输完成中断 */
                                                    usba_ep_writel(ep, CTL_ENB, USBA_TX_COMPLETE);
                                                }
                                            }
                                        }
                                    }

                                    if (req->last_transaction) {
                                        usba_ep_writel(ep, CTL_DIS, USBA_TX_PK_RDY);
                                        usba_ep_writel(ep, CTL_ENB, USBA_TX_COMPLETE);
                                    }
                                }

                                epstatus = usba_ep_readl(ep, STA);
                                epctrl = usba_ep_readl(ep, CTL);

                                req = NULL;
                                if (!list_empty(&ep->queue)) {
                                    req = list_entry(ep->queue.next,
                                             struct usba_request, queue);
                                }

                                /* 发生了 IN data 传输完成中断 */
                                if ((epstatus & epctrl) & USBA_TX_COMPLETE) {
                                    /* Clear the TX_COMPLT flag of UDPHS_EPTSTAx */
                                    /* 清除 UDPHS_EPTSTAx 寄存器中的 TX_COMPLT 标志位 */
                                    usba_ep_writel(ep, CLR_STA, USBA_TX_COMPLETE);

                                    switch (ep->state) {
                                    case DATA_STAGE_IN: 
                                        /* 使能 OUT data 接收中断 */
                                        usba_ep_writel(ep, CTL_ENB, USBA_RX_BK_RDY);
                                        /* 关闭 IN data 传输完成 中断 */
                                        usba_ep_writel(ep, CTL_DIS, USBA_TX_COMPLETE);
                                        ep->state = STATUS_STAGE_OUT;
                                        break;
                                    }
                                }
                                epstatus = usba_ep_readl(ep, STA);
                                epctrl = usba_ep_readl(ep, CTL);

                                req = NULL;
                                if (!list_empty(&ep->queue)) {
                                    req = list_entry(ep->queue.next,
                                             struct usba_request, queue);
                                }

                                if ((epstatus & epctrl) & USBA_RX_BK_RDY) {
                                    switch (ep->state) {
                                    case STATUS_STAGE_OUT: 
                                        /* Clear the RXRDY_TXKL flag of UDPHS_EPTSTAx. */
                                        /* 清除 UDPHS_EPTSTAx 寄存器中的 RXRDY_TXKL 标志位 */
                                        usba_ep_writel(ep, CLR_STA, USBA_RX_BK_RDY);
                                        /* 关闭 OUT data 接收完成中断 */
                                        usba_ep_writel(ep, CTL_DIS, USBA_RX_BK_RDY);

                                        if (req) {
                                            list_del_init(&req->queue); <tag40>
                                            request_complete(ep, req, 0);
                                            static void request_complete(struct usba_ep *ep, struct usba_request *req, int status)
                                            {
                                                struct usba_udc *udc = ep->udc;

                                                if (req->req.status == -EINPROGRESS) { //
                                                    req->req.status = status;
                                                }

                                                DBG(DBG_GADGET | DBG_REQ,
                                                    "%s: req %p complete: status %d, actual %u\n",
                                                    ep->ep.name, req, req->req.status, req->req.actual);

                                                spin_unlock(&udc->lock);
                                                usb_gadget_giveback_request(&ep->ep, &req->req);
                                                void usb_gadget_giveback_request(struct usb_ep *ep,
                                                        struct usb_request *req)
                                                {
                                                    /* composite_setup_complete */
                                                    req->complete(ep, req);
                                                    static void composite_setup_complete(struct usb_ep *ep,
                                                                                         struct usb_request *req)
                                                    {
                                                        struct usb_composite_dev *cdev;

                                                        cdev = req->context;

                                                        if (cdev->req == req) {
                                                            cdev->setup_pending = false;
                                                        }
                                                    }
                                                }
                                                spin_lock(&udc->lock);
                                            }
                                        }
                                        ep->state = WAIT_FOR_SETUP;
                                        break;
                                    }
                                }
                            }
                            break;
                        case 2:
        					case2_usba_control_irq(udc, &udc->usba_ep[i]);
                            static void case2_usba_control_irq(struct usba_udc *udc, struct usba_ep *ep)
                            {
                                struct usba_request *req;
                                u32 epstatus;
                                u32 epctrl;

                                epstatus = usba_ep_readl(ep, STA);
                                epctrl = usba_ep_readl(ep, CTL);

                                req = NULL;

                                if (epstatus & USBA_RX_SETUP) {
                                    union {
                                        struct usb_ctrlrequest crq;
                                        unsigned long data[2];
                                    } crq;
                                    unsigned int pkt_len;
                                    int ret;

                                    pkt_len = USBA_BFEXT(BYTE_COUNT, usba_ep_readl(ep, STA));

                                    memcpy_fromio(crq.data, ep->fifo, sizeof(crq));

                                    /* Free up one bank in the FIFO so that we can
                                     * generate or receive a reply right away. */
                                    /* 清除 UDPHS_EPTSTAx 寄存器中的 RX_SETUP 标志位 */
                                    usba_ep_writel(ep, CLR_STA, USBA_RX_SETUP);

                                    if (crq.crq.bRequestType & USB_DIR_IN) {
                                    } else {
                                        if (crq.crq.wLength != cpu_to_le16(0)) {
                                        }
                                        else {
                                            ep->state = STATUS_STAGE_IN;
                                        }
                                    }

                                    ret = -1;
                                    if (ep->index == 0) { //
                                        ret = case2_handle_ep0_setup(udc, ep, &crq.crq);
                                        static int case2_handle_ep0_setup(struct usba_udc *udc, struct usba_ep *ep,
                                                struct usb_ctrlrequest *crq)
                                        {
                                            int retval = 0;

                                            switch (crq->bRequest) {
                                            case USB_REQ_SET_ADDRESS:
                                                set_address(udc, le16_to_cpu(crq->wValue));
                                                static inline void set_address(struct usba_udc *udc, unsigned int addr)
                                                {
                                                    u32 regval;

                                                    /* 读端点控制寄存器的值 */
                                                    regval = usba_readl(udc, CTRL);
                                                    regval = USBA_BFINS(DEV_ADDR, addr, regval);
                                                    /* 写 CTRL寄存器, 设置设备地址. */
                                                    usba_writel(udc, CTRL, regval);
                                                }
                                                send_status(udc, ep);
                                                static void send_status(struct usba_udc *udc, struct usba_ep *ep)
                                                {
                                                    ep->state = STATUS_STAGE_IN;
                                                    /* 表示ep->fifo已经写入数据, 可以进行数据传输. */
                                                    usba_ep_writel(ep, SET_STA, USBA_TX_PK_RDY);
                                                    /* 使能 IN data 传输完成中断 */
                                                    usba_ep_writel(ep, CTL_ENB, USBA_TX_COMPLETE);
                                                }
                                                ep->state = STATUS_STAGE_ADDR;
                                                break;
                                            }

                                            return retval;
                                        }
                                    }
                                }
                            }
                            break;
                        case 3:
        					case3_usba_control_irq(udc, &udc->usba_ep[i]);
                            static void case3_usba_control_irq(struct usba_udc *udc, struct usba_ep *ep)
                            {
                                struct usba_request *req;
                                u32 epstatus;
                                u32 epctrl;

                                epstatus = usba_ep_readl(ep, STA);
                                epctrl = usba_ep_readl(ep, CTL);

                                req = NULL;

                                /* 发生了 tx 数据传输完成中断 */
                                if ((epstatus & epctrl) & USBA_TX_COMPLETE) {
                                    /* 清除 UDPHS_EPTSTAx 寄存器中的 TX_COMPLT 标志位 */
                                    usba_ep_writel(ep, CLR_STA, USBA_TX_COMPLETE);

                                    switch (ep->state) {
                                    case STATUS_STAGE_ADDR:
                                        /* Activate our new address */
                                        /* 使能写入的设备地址. */
                                        usba_writel(udc, CTRL, (usba_readl(udc, CTRL) | USBA_FADDR_EN));
                                        /* 关闭 IN data 传输完成 中断 */
                                        usba_ep_writel(ep, CTL_DIS, USBA_TX_COMPLETE);
                                        ep->state = WAIT_FOR_SETUP;
                                        break;
                                    }
                                }
                            }
                            break;
                        case 4:
        					case4_usba_control_irq(udc, &udc->usba_ep[i]);
                            static void case4_usba_control_irq(struct usba_udc *udc, struct usba_ep *ep)
                            {
                                struct usba_request *req;
                                u32 epstatus;
                                u32 epctrl;

                                epstatus = usba_ep_readl(ep, STA);
                                epctrl = usba_ep_readl(ep, CTL);

                                req = NULL;

                                if (epstatus & USBA_RX_SETUP) { //
                                    union {
                                        struct usb_ctrlrequest crq;
                                        unsigned long data[2];
                                    } crq;
                                    unsigned int pkt_len;
                                    int ret;

                                    pkt_len = USBA_BFEXT(BYTE_COUNT, usba_ep_readl(ep, STA));

                                    memcpy_fromio(crq.data, ep->fifo, sizeof(crq));

                                    /* Free up one bank in the FIFO so that we can
                                     * generate or receive a reply right away. */
                                    /* 清除 UDPHS_EPTSTAx 寄存器中的 RX_SETUP 标志位 */
                                    usba_ep_writel(ep, CLR_STA, USBA_RX_SETUP);

                                    if (crq.crq.bRequestType & USB_DIR_IN) { //
                                        /*
                                         * The USB 2.0 spec states that "if wLength is
                                         * zero, there is no data transfer phase."
                                         * However, testusb #14 seems to actually
                                         * expect a data phase even if wLength = 0...
                                         */
                                        ep->state = DATA_STAGE_IN;
                                    }

                                    ret = -1;
                                    if (ep->index == 0) { //
                                        ret = case4_handle_ep0_setup(udc, ep, &crq.crq);
                                        static int case4_handle_ep0_setup(struct usba_udc *udc, struct usba_ep *ep,
                                                struct usb_ctrlrequest *crq)
                                        {
                                            int retval = 0;

                                            switch (crq->bRequest) {
                                            default:
                                                spin_unlock(&udc->lock);
                                                /* composite_setup */
                                                retval = udc->driver->setup(&udc->gadget, crq);
                                                int composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
                                                {
                                                    struct usb_composite_dev	*cdev = get_gadget_data(gadget);
                                                    struct usb_request		*req = cdev->req;
                                                    int				value = -EOPNOTSUPP;
                                                    int				status = 0;
                                                    u16				w_index = le16_to_cpu(ctrl->wIndex);
                                                    u8				intf = w_index & 0xFF;
                                                    u16				w_value = le16_to_cpu(ctrl->wValue);
                                                    u16				w_length = le16_to_cpu(ctrl->wLength);
                                                    struct usb_function		*f = NULL;
                                                    u8				endp;

                                                    /* partial re-init of the response message; the function or the
                                                     * gadget might need to intercept e.g. a control-OUT completion
                                                     * when we delegate to it.
                                                     */
                                                    req->zero = 0;
                                                    req->context = cdev;
                                                    req->complete = composite_setup_complete;
                                                    req->length = 0;
                                                    gadget->ep0->driver_data = cdev;

                                                    switch (ctrl->bRequest) {

                                                    /* we handle all standard USB descriptors */
                                                    case USB_REQ_GET_DESCRIPTOR: //
                                                        switch (w_value >> 8) {

                                                        case USB_DT_DEVICE: //
                                                            cdev->desc.bNumConfigurations = count_configs(cdev, USB_DT_DEVICE);
                                                            cdev->desc.bMaxPacketSize0 = cdev->gadget->ep0->maxpacket;
                                                            if (gadget_is_superspeed(gadget))
                                                            {
                                                            } else {
                                                                cdev->desc.bcdUSB = cpu_to_le16(0x0200);
                                                            }

                                                            value = min(w_length, (u16) sizeof cdev->desc);
                                                            memcpy(req->buf, &cdev->desc, value);
                                                            break;
                                                        }
                                                        break;
                                                    }

                                                    /* respond with data transfer before status phase? */
                                                    if (value >= 0 && value != USB_GADGET_DELAYED_STATUS) {
                                                        req->length = value;
                                                        req->context = cdev;
                                                        req->zero = value < w_length;
                                                        value = composite_ep0_queue(cdev, req, GFP_ATOMIC);
                                                        static int composite_ep0_queue(struct usb_composite_dev *cdev,
                                                                struct usb_request *req, gfp_t gfp_flags)
                                                        {
                                                            int ret;

                                                            ret = usb_ep_queue(cdev->gadget->ep0, req, gfp_flags);
                                                            static inline int usb_ep_queue(struct usb_ep *ep,
                                                                               struct usb_request *req, gfp_t gfp_flags)
                                                            {
                                                                /* usba_ep_queue */
                                                                return ep->ops->queue(ep, req, gfp_flags);
                                                                static int
                                                                usba_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
                                                                {
                                                                    struct usba_request *req = to_usba_req(_req);
                                                                    struct usba_ep *ep = to_usba_ep(_ep);
                                                                    struct usba_udc *udc = ep->udc;
                                                                    unsigned long flags;
                                                                    int ret;

                                                                    req->submitted = 0;
                                                                    req->using_dma = 0;
                                                                    req->last_transaction = 0;

                                                                    _req->status = -EINPROGRESS;
                                                                    _req->actual = 0;

                                                                    /* May have received a reset since last time we checked */
                                                                    ret = -ESHUTDOWN;
                                                                    spin_lock_irqsave(&udc->lock, flags);
                                                                    if (ep->ep.desc) { //
                                                                        list_add_tail(&req->queue, &ep->queue); <tag42>

                                                                        if ((!ep_is_control(ep) && ep->is_in) ||
                                                                            (ep_is_control(ep)
                                                                                && (ep->state == DATA_STAGE_IN
                                                                                    || ep->state == STATUS_STAGE_IN))) {
                                                                            /* 使能tx包准备ok,和tx传输错误中断. */
                                                                            usba_ep_writel(ep, CTL_ENB, USBA_TX_PK_RDY);
                                                                        }
                                                                        ret = 0;
                                                                    }
                                                                    spin_unlock_irqrestore(&udc->lock, flags);

                                                                    return ret;
                                                                }
                                                            }
                                                            if (ret == 0) {
                                                                if (cdev->req == req) {
                                                                    cdev->setup_pending = true;
                                                                }
                                                            }

                                                            return ret;
                                                        }
                                                    }

                                                    /* device either stalls (value < 0) or reports success */
                                                    return value;
                                                }
                                                spin_lock(&udc->lock);
                                            }

                                            return retval;
                                        }
                                    }
                                }
                            }
                            break;
                        case 5:
        					case5_usba_control_irq(udc, &udc->usba_ep[i]);
                            static void case5_usba_control_irq(struct usba_udc *udc, struct usba_ep *ep)
                            {
                                struct usba_request *req;
                                u32 epstatus;
                                u32 epctrl;

                                epstatus = usba_ep_readl(ep, STA);
                                epctrl = usba_ep_readl(ep, CTL);

                                req = NULL;
                                if (!list_empty(&ep->queue)) {
                                    req = list_entry(ep->queue.next, struct usba_request, queue);
                                }

                                if ((epctrl & USBA_TX_PK_RDY) && !(epstatus & USBA_TX_PK_RDY)) {
                                    if (req->submitted) {
                                    }
                                    else {
                                        case1_submit_request(ep, req);
                                        static void case1_submit_request(struct usba_ep *ep, struct usba_request *req)
                                        {
                                            req->req.actual = 0;
                                            req->submitted = 1;

                                            if (req->using_dma) {

                                            } else {
                                                next_fifo_transaction(ep, req);
                                                static void next_fifo_transaction(struct usba_ep *ep, struct usba_request *req)
                                                {
                                                    unsigned int transaction_len;

                                                    transaction_len = req->req.length - req->req.actual;
                                                    req->last_transaction = 1;

                                                    memcpy_toio(ep->fifo, req->req.buf + req->req.actual, transaction_len); <tag39>
                                                    /* 表示ep->fifo已经写入数据, 可以进行数据传输. */
                                                    usba_ep_writel(ep, SET_STA, USBA_TX_PK_RDY);
                                                    req->req.actual += transaction_len;
                                                }
                                                if (req->last_transaction) {
                                                    //USBA_EPT_CTL_DIS
                                                    /* 关闭tx包准备OK, 和tx传输错误中断 */
                                                    usba_ep_writel(ep, CTL_DIS, USBA_TX_PK_RDY);
                                                    /* 使能 IN data 传输完成中断 */
                                                    usba_ep_writel(ep, CTL_ENB, USBA_TX_COMPLETE);
                                                }
                                            }
                                        }
                                        
                                    }

                                    if (req->last_transaction) {
                                        /* 关闭tx包准备OK, 和tx传输错误中断 */
                                        usba_ep_writel(ep, CTL_DIS, USBA_TX_PK_RDY);
                                        /* 使能 IN data 传输完成中断 */
                                        usba_ep_writel(ep, CTL_ENB, USBA_TX_COMPLETE);
                                    }
                                }

                                epstatus = usba_ep_readl(ep, STA);
                                epctrl = usba_ep_readl(ep, CTL);

                                req = NULL;
                                if (!list_empty(&ep->queue)) {
                                    req = list_entry(ep->queue.next, struct usba_request, queue);
                                }

                                if ((epstatus & epctrl) & USBA_TX_COMPLETE) {
                                    usba_ep_writel(ep, CLR_STA, USBA_TX_COMPLETE);

                                    switch (ep->state) {
                                    case DATA_STAGE_IN: 
                                        /* 使能 OUT data 接收中断 */
                                        usba_ep_writel(ep, CTL_ENB, USBA_RX_BK_RDY);
                                        /* 关闭 IN data 传输完成 中断 */
                                        usba_ep_writel(ep, CTL_DIS, USBA_TX_COMPLETE);
                                        ep->state = STATUS_STAGE_OUT;
                                        break;
                                    }
                                }
                                epstatus = usba_ep_readl(ep, STA);
                                epctrl = usba_ep_readl(ep, CTL);

                                req = NULL;
                                if (!list_empty(&ep->queue)) {
                                    req = list_entry(ep->queue.next, struct usba_request, queue);
                                }

                                if ((epstatus & epctrl) & USBA_RX_BK_RDY) {
                                    switch (ep->state) {
                                    case STATUS_STAGE_OUT: 
                                        /* 清除 UDPHS_EPTSTAx 寄存器中的 RXRDY_TXKL 标志位 */
                                        usba_ep_writel(ep, CLR_STA, USBA_RX_BK_RDY);
                                        /* 关闭 OUT data 接收完成中断 */
                                        usba_ep_writel(ep, CTL_DIS, USBA_RX_BK_RDY);

                                        if (req) {
                                            list_del_init(&req->queue);
                                            //request_complete(ep, req, 0);
                                        }
                                        ep->state = WAIT_FOR_SETUP;
                                        break;
                                    }
                                }
                            }
                            break;
                        case 6:
        					case6_usba_control_irq(udc, &udc->usba_ep[i]);
                            static void case6_usba_control_irq(struct usba_udc *udc, struct usba_ep *ep)
                            {
                                struct usba_request *req;
                                u32 epstatus;
                                u32 epctrl;

                            restart:
                                epstatus = usba_ep_readl(ep, STA);
                                epctrl = usba_ep_readl(ep, CTL);

                                req = NULL;

                                if (epstatus & USBA_RX_SETUP) {
                                    union {
                                        struct usb_ctrlrequest crq;
                                        unsigned long data[2];
                                    } crq;
                                    unsigned int pkt_len;
                                    int ret;

                                    pkt_len = USBA_BFEXT(BYTE_COUNT, usba_ep_readl(ep, STA));

                                    memcpy_fromio(crq.data, ep->fifo, sizeof(crq));

                                    /* Free up one bank in the FIFO so that we can
                                     * generate or receive a reply right away. */
                                    usba_ep_writel(ep, CLR_STA, USBA_RX_SETUP);

                                    if (crq.crq.bRequestType & USB_DIR_IN) { //
                                        /*
                                         * The USB 2.0 spec states that "if wLength is
                                         * zero, there is no data transfer phase."
                                         * However, testusb #14 seems to actually
                                         * expect a data phase even if wLength = 0...
                                         */
                                        ep->state = DATA_STAGE_IN;
                                    }

                                    ret = -1;
                                    if (ep->index == 0) { //
                                        ret = case6_handle_ep0_setup(udc, ep, &crq.crq);
                                        //handle_ep0_setup(udc, ep, &crq.crq);
                                        static int case6_handle_ep0_setup(struct usba_udc *udc, struct usba_ep *ep,
                                                struct usb_ctrlrequest *crq)
                                        {
                                            int retval = 0;

                                            switch (crq->bRequest) {
                                            default:
                                                spin_unlock(&udc->lock);
                                                /* composite_setup */
                                                retval = udc->driver->setup(&udc->gadget, crq);
                                                int composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
                                                {
                                                    struct usb_composite_dev	*cdev = get_gadget_data(gadget);
                                                    struct usb_request		*req = cdev->req;
                                                    int				value = -EOPNOTSUPP;
                                                    int				status = 0;
                                                    u16				w_index = le16_to_cpu(ctrl->wIndex);
                                                    u8				intf = w_index & 0xFF;
                                                    u16				w_value = le16_to_cpu(ctrl->wValue);
                                                    u16				w_length = le16_to_cpu(ctrl->wLength);
                                                    struct usb_function		*f = NULL;
                                                    u8				endp;

                                                    /* partial re-init of the response message; the function or the
                                                     * gadget might need to intercept e.g. a control-OUT completion
                                                     * when we delegate to it.
                                                     */
                                                    req->zero = 0;
                                                    req->context = cdev;
                                                    req->complete = composite_setup_complete;
                                                    req->length = 0;
                                                    gadget->ep0->driver_data = cdev;

                                                    switch (ctrl->bRequest) {

                                                    /* we handle all standard USB descriptors */
                                                    case USB_REQ_GET_DESCRIPTOR:
                                                        switch (w_value >> 8) {
                                                        case USB_DT_CONFIG:
                                                            value = config_desc(cdev, w_value);
                                                            static int config_desc(struct usb_composite_dev *cdev,
                                                                                                        unsigned w_value)
                                                            {
                                                                struct usb_gadget		*gadget = cdev->gadget;
                                                                struct usb_configuration	*c;
                                                                struct list_head		*pos;
                                                                u8				type = w_value >> 8;
                                                                enum usb_device_speed		speed = USB_SPEED_UNKNOWN;

                                                                if (gadget_is_dualspeed(gadget)) {
                                                                    int	hs = 0;
                                                                    if (gadget->speed == USB_SPEED_HIGH) {
                                                                        hs = 1;
                                                                    }

                                                                    if (hs) {//
                                                                        speed = USB_SPEED_HIGH;
                                                                    }

                                                                }

                                                                /* This is a lookup by config *INDEX* */
                                                                /* 取要获取的配置描述符的索引值 */
                                                                w_value &= 0xff;

                                                                /* loopback config */
                                                                pos = &cdev->configs;
                                                                c = cdev->os_desc_config;

                                                                pos = pos->next;
                                                                {
                                                                    c = list_entry(pos, typeof(*c), list);

                                                                    /* 找到对应索引值的配置描述符 */
                                                                    if (w_value == 0) { //
                                                                        return config_buf(c, speed, cdev->req->buf, type);
                                                                        /* 复制config 的内容到req->buf */
                                                                        static int config_buf(struct usb_configuration *config,
                                                                                enum usb_device_speed speed, void *buf, u8 type) <tag43>
                                                                        {
                                                                            struct usb_config_descriptor	*c = buf;
                                                                            void				*next = buf + USB_DT_CONFIG_SIZE;
                                                                            int				len;
                                                                            struct usb_function		*f;
                                                                            int				status;

                                                                            len = USB_COMP_EP0_BUFSIZ - USB_DT_CONFIG_SIZE;
                                                                            /* write the config descriptor */
                                                                            c = buf;
                                                                            c->bLength = USB_DT_CONFIG_SIZE;
                                                                            c->bDescriptorType = type;
                                                                            /* wTotalLength is written later */
                                                                            c->bNumInterfaces = config->next_interface_id;
                                                                            c->bConfigurationValue = config->bConfigurationValue;
                                                                            c->iConfiguration = config->iConfiguration;
                                                                            c->bmAttributes =
                                                                                    USB_CONFIG_ATT_ONE | config->bmAttributes;
                                                                            c->bMaxPower = encode_bMaxPower(speed, config);
                                                                            static u8 encode_bMaxPower(enum usb_device_speed speed,
                                                                                    struct usb_configuration *c)
                                                                            {
                                                                                unsigned val;

                                                                                if (c->MaxPower) {
                                                                                }
                                                                                else {
                                                                                    val = CONFIG_USB_GADGET_VBUS_DRAW;
                                                                                }

                                                                                switch (speed) {
                                                                                default:
                                                                                    return DIV_ROUND_UP(val, 2);
                                                                                }
                                                                            }

                                                                            /* add each function's descriptors */
                                                                            list_for_each_entry(f, &config->functions, list) { // 循环一次.
                                                                                struct usb_descriptor_header **descriptors;

                                                                                switch (speed) {

                                                                                case USB_SPEED_HIGH: //
                                                                                    descriptors = f->hs_descriptors;
                                                                                    break;
                                                                                }

                                                                                
                                                                                status = usb_descriptor_fillbuf(next, len,
                                                                                    (const struct usb_descriptor_header **) descriptors);
                                                                                int usb_descriptor_fillbuf(void *buf, unsigned buflen,
                                                                                        const struct usb_descriptor_header **src)
                                                                                {
                                                                                    u8	*dest = buf;

                                                                                    /* fill buffer from src[] until null descriptor ptr */
                                                                                    for (; NULL != *src; src++) {
                                                                                        unsigned		len = (*src)->bLength;

                                                                                        memcpy(dest, *src, len);
                                                                                        buflen -= len;
                                                                                        dest += len;
                                                                                    }
                                                                                    return dest - (u8 *)buf;
                                                                                }

                                                                                len -= status;
                                                                                next += status;
                                                                            }

                                                                            len = next - buf;
                                                                            c->wTotalLength = cpu_to_le16(len);
                                                                            return len;
                                                                        }
                                                                    }
                                                                }
                                                                return -EINVAL;
                                                            }
                                                            if (value >= 0) {
                                                                value = min(w_length, (u16) value);
                                                            }
                                                            break;
                                                        }
                                                        break;
                                                    }

                                                    /* respond with data transfer before status phase? */
                                                    if (value >= 0 && value != USB_GADGET_DELAYED_STATUS) {
                                                        req->length = value;
                                                        req->context = cdev;
                                                        req->zero = value < w_length;
                                                        value = composite_ep0_queue(cdev, req, GFP_ATOMIC);
                                                        static int composite_ep0_queue(struct usb_composite_dev *cdev,
                                                                struct usb_request *req, gfp_t gfp_flags)
                                                        {
                                                            int ret;

                                                            ret = usb_ep_queue(cdev->gadget->ep0, req, gfp_flags);
                                                            static inline int usb_ep_queue(struct usb_ep *ep,
                                                                               struct usb_request *req, gfp_t gfp_flags)
                                                            {
                                                                /* usba_ep_queue */
                                                                return ep->ops->queue(ep, req, gfp_flags);
                                                                static int usba_ep_queue(struct usb_ep *_ep,
                                                                            struct usb_request *_req, gfp_t gfp_flags)
                                                                {
                                                                    struct usba_request *req = to_usba_req(_req);
                                                                    struct usba_ep *ep = to_usba_ep(_ep);
                                                                    struct usba_udc *udc = ep->udc;
                                                                    unsigned long flags;
                                                                    int ret;

                                                                    req->submitted = 0;
                                                                    req->using_dma = 0;
                                                                    req->last_transaction = 0;

                                                                    _req->status = -EINPROGRESS;
                                                                    _req->actual = 0;

                                                                    /* May have received a reset since last time we checked */
                                                                    ret = -ESHUTDOWN;
                                                                    spin_lock_irqsave(&udc->lock, flags);
                                                                    if (ep->ep.desc) { //
                                                                        list_add_tail(&req->queue, &ep->queue); <tag38>

                                                                        if ((!ep_is_control(ep) && ep->is_in) ||
                                                                            (ep_is_control(ep)
                                                                                && (ep->state == DATA_STAGE_IN
                                                                                    || ep->state == STATUS_STAGE_IN))) {
                                                                            /* Enable TX Packet Ready/Transaction Error Interrup.*/
                                                                            /* 使能tx包准备ok,和tx传输错误中断. */
                                                                            usba_ep_writel(ep, CTL_ENB, USBA_TX_PK_RDY);
                                                                        }
                                                                        ret = 0;
                                                                    }
                                                                    spin_unlock_irqrestore(&udc->lock, flags);

                                                                    return ret;
                                                                }
                                                            }
                                                            if (ret == 0) {
                                                                if (cdev->req == req) {
                                                                    cdev->setup_pending = true;
                                                                }
                                                            }

                                                            return ret;
                                                        }
                                                    }

                                                    /* device either stalls (value < 0) or reports success */
                                                    return value;
                                                }
                                                spin_lock(&udc->lock);
                                            }

                                            return retval;
                                        }
                                    }
                                }
                            }
                            break;
                        case 7:
        					case7_usba_control_irq(udc, &udc->usba_ep[i]);
                            static void case7_usba_control_irq(struct usba_udc *udc, struct usba_ep *ep)
                            {
                                struct usba_request *req;
                                u32 epstatus;
                                u32 epctrl;

                                epstatus = usba_ep_readl(ep, STA);
                                epctrl = usba_ep_readl(ep, CTL);

                                req = NULL;
                                if (!list_empty(&ep->queue)) {
                                    req = list_entry(ep->queue.next, struct usba_request, queue);
                                }

                                /* epctrl & USBA_TX_PK_RDY 值为1, 表示tx包准备ok时将产生中断. */
                                if ((epctrl & USBA_TX_PK_RDY) && !(epstatus & USBA_TX_PK_RDY)) {
                                    if (req->submitted) {
                                    }
                                    else {
                                        submit_request(ep, req);
                                        static void submit_request(struct usba_ep *ep, struct usba_request *req)
                                        {
                                            req->req.actual = 0;
                                            req->submitted = 1;

                                            if (req->using_dma) {

                                            } else {
                                                /* 告诉usb device控制器可以开始传输data. */
                                                next_fifo_transaction(ep, req);
                                                static void next_fifo_transaction(struct usba_ep *ep, struct usba_request *req)
                                                {
                                                    unsigned int transaction_len;

                                                    transaction_len = req->req.length - req->req.actual;
                                                    req->last_transaction = 1;

                                                    memcpy_toio(ep->fifo, req->req.buf + req->req.actual, transaction_len); <tag39>
                                                    /* 表示ep->fifo已经写入数据, 可以进行数据传输. */
                                                    usba_ep_writel(ep, SET_STA, USBA_TX_PK_RDY);
                                                    req->req.actual += transaction_len;
                                                }
                                                if (req->last_transaction) {
                                                    /* 关闭tx包准备OK, 和tx传输错误中断 */
                                                    usba_ep_writel(ep, CTL_DIS, USBA_TX_PK_RDY);
                                                    /* 使能 IN data 传输完成中断 */
                                                    usba_ep_writel(ep, CTL_ENB, USBA_TX_COMPLETE);
                                                }
                                            }
                                        }
                                    }

                                    if (req->last_transaction) {
                                        /* 关闭tx包准备OK, 和tx传输错误中断 */
                                        usba_ep_writel(ep, CTL_DIS, USBA_TX_PK_RDY);
                                        /* 使能 IN data 传输完成中断 */
                                        usba_ep_writel(ep, CTL_ENB, USBA_TX_COMPLETE);
                                    }
                                }

                                epstatus = usba_ep_readl(ep, STA);
                                epctrl = usba_ep_readl(ep, CTL);

                                req = NULL;
                                if (!list_empty(&ep->queue)) {
                                    req = list_entry(ep->queue.next,
                                             struct usba_request, queue);
                                }

                                /* 发生了 IN data 传输完成中断 */
                                if ((epstatus & epctrl) & USBA_TX_COMPLETE) {
                                    /* 清除 UDPHS_EPTSTAx 寄存器中的 TX_COMPLT 标志位 */
                                    usba_ep_writel(ep, CLR_STA, USBA_TX_COMPLETE);

                                    switch (ep->state) {
                                    case DATA_STAGE_IN: 
                                        /* 使能 OUT data 接收中断 */
                                        usba_ep_writel(ep, CTL_ENB, USBA_RX_BK_RDY);
                                        /* 关闭 IN data 传输完成 中断 */
                                        usba_ep_writel(ep, CTL_DIS, USBA_TX_COMPLETE);
                                        ep->state = STATUS_STAGE_OUT;
                                        break;
                                    }
                                }
                                epstatus = usba_ep_readl(ep, STA);
                                epctrl = usba_ep_readl(ep, CTL);

                                req = NULL;
                                if (!list_empty(&ep->queue)) {
                                    req = list_entry(ep->queue.next,struct usba_request, queue);
                                }

                                if ((epstatus & epctrl) & USBA_RX_BK_RDY) {
                                    switch (ep->state) {
                                    case STATUS_STAGE_OUT: 
                                        /* 清除 UDPHS_EPTSTAx 寄存器中的 RXRDY_TXKL 标志位 */
                                        usba_ep_writel(ep, CLR_STA, USBA_RX_BK_RDY);
                                        /* 关闭 OUT data 接收完成中断 */
                                        usba_ep_writel(ep, CTL_DIS, USBA_RX_BK_RDY);

                                        if (req) {
                                            list_del_init(&req->queue);
                                            //request_complete(ep, req, 0);
                                        }
                                        ep->state = WAIT_FOR_SETUP;
                                        break;
                                    }
                                }
                            }
                            break;
                        case 8:
        					case8_usba_control_irq(udc, &udc->usba_ep[i]);
                            static void case8_usba_control_irq(struct usba_udc *udc, struct usba_ep *ep)
                            {
                                struct usba_request *req;
                                u32 epstatus;
                                u32 epctrl;

                                epstatus = usba_ep_readl(ep, STA);
                                epctrl = usba_ep_readl(ep, CTL);

                                req = NULL;

                                /* 当收到 setup 包时, 置位RX_SETUP. */
                                if (epstatus & USBA_RX_SETUP) {
                                    union {
                                        struct usb_ctrlrequest crq;
                                        unsigned long data[2];
                                    } crq;
                                    unsigned int pkt_len;
                                    int ret;

                                    pkt_len = USBA_BFEXT(BYTE_COUNT, usba_ep_readl(ep, STA));

                                    memcpy_fromio(crq.data, ep->fifo, sizeof(crq));

                                    /* Free up one bank in the FIFO so that we can
                                     * generate or receive a reply right away. */
                                    /* 清除 UDPHS_EPTSTAx 寄存器中的 RX_SETUP 标志位 */
                                    usba_ep_writel(ep, CLR_STA, USBA_RX_SETUP);

                                    if (crq.crq.bRequestType & USB_DIR_IN) {
                                        /*
                                         * The USB 2.0 spec states that "if wLength is
                                         * zero, there is no data transfer phase."
                                         * However, testusb #14 seems to actually
                                         * expect a data phase even if wLength = 0...
                                         */
                                        ep->state = DATA_STAGE_IN;
                                    }

                                    ret = -1;
                                    if (ep->index == 0) {
                                        ret = case8_handle_ep0_setup(udc, ep, &crq.crq);
                                        static int case8_handle_ep0_setup(struct usba_udc *udc, struct usba_ep *ep,
                                                struct usb_ctrlrequest *crq)
                                        {
                                            int retval = 0;

                                            switch (crq->bRequest) {
                                            default:
                                                spin_unlock(&udc->lock);
                                                /* composite_setup */
                                                retval = udc->driver->setup(&udc->gadget, crq);
                                                int composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
                                                {
                                                    struct usb_composite_dev	*cdev = get_gadget_data(gadget);
                                                    struct usb_request		*req = cdev->req;
                                                    int				value = -EOPNOTSUPP;
                                                    int				status = 0;
                                                    u16				w_index = le16_to_cpu(ctrl->wIndex);
                                                    u8				intf = w_index & 0xFF;
                                                    u16				w_value = le16_to_cpu(ctrl->wValue);
                                                    u16				w_length = le16_to_cpu(ctrl->wLength);
                                                    struct usb_function		*f = NULL;
                                                    u8				endp;

                                                    /* partial re-init of the response message; the function or the
                                                     * gadget might need to intercept e.g. a control-OUT completion
                                                     * when we delegate to it.
                                                     */
                                                    req->zero = 0;
                                                    req->context = cdev;
                                                    req->complete = composite_setup_complete;
                                                    req->length = 0;
                                                    gadget->ep0->driver_data = cdev;

                                                    switch (ctrl->bRequest) {

                                                    /* we handle all standard USB descriptors */
                                                    case USB_REQ_GET_DESCRIPTOR: //
                                                        switch (w_value >> 8) {
                                                        case USB_DT_CONFIG: //
                                                            value = config_desc(cdev, w_value);
                                                            static int config_desc(struct usb_composite_dev *cdev,
                                                                                                        unsigned w_value)
                                                            {
                                                                struct usb_gadget		*gadget = cdev->gadget;
                                                                struct usb_configuration	*c;
                                                                struct list_head		*pos;
                                                                u8				type = w_value >> 8;
                                                                enum usb_device_speed		speed = USB_SPEED_UNKNOWN;

                                                                if (gadget_is_dualspeed(gadget)) {
                                                                    int	hs = 0;
                                                                    if (gadget->speed == USB_SPEED_HIGH) {
                                                                        hs = 1;
                                                                    }

                                                                    if (hs) {//
                                                                        speed = USB_SPEED_HIGH;
                                                                    }

                                                                }

                                                                /* This is a lookup by config *INDEX* */
                                                                w_value &= 0xff;

                                                                pos = &cdev->configs;
                                                                c = cdev->os_desc_config;

                                                                pos = pos->next;
                                                                {
                                                                    c = list_entry(pos, typeof(*c), list);

                                                                    if (w_value == 0) { //
                                                                        return config_buf(c, speed, cdev->req->buf, type);
                                                                        static int config_buf(struct usb_configuration *config,
                                                                                enum usb_device_speed speed, void *buf, u8 type)
                                                                        {
                                                                            struct usb_config_descriptor	*c = buf;
                                                                            void				*next = buf + USB_DT_CONFIG_SIZE;
                                                                            int				len;
                                                                            struct usb_function		*f;
                                                                            int				status;

                                                                            len = USB_COMP_EP0_BUFSIZ - USB_DT_CONFIG_SIZE;
                                                                            /* write the config descriptor */
                                                                            c = buf;
                                                                            c->bLength = USB_DT_CONFIG_SIZE;
                                                                            c->bDescriptorType = type;
                                                                            /* wTotalLength is written later */
                                                                            c->bNumInterfaces = config->next_interface_id;
                                                                            c->bConfigurationValue = config->bConfigurationValue;
                                                                            c->iConfiguration = config->iConfiguration;
                                                                            c->bmAttributes = USB_CONFIG_ATT_ONE | config->bmAttributes;
                                                                            c->bMaxPower = encode_bMaxPower(speed, config);
                                                                            static u8 encode_bMaxPower(enum usb_device_speed speed,
                                                                                    struct usb_configuration *c)
                                                                            {
                                                                                unsigned val;

                                                                                if (c->MaxPower) {
                                                                                }
                                                                                else { //
                                                                                    val = CONFIG_USB_GADGET_VBUS_DRAW;
                                                                                }

                                                                                switch (speed) {
                                                                                default: //
                                                                                    return DIV_ROUND_UP(val, 2);
                                                                                }
                                                                            }

                                                                            /* add each function's descriptors */
                                                                            list_for_each_entry(f, &config->functions, list) { // 循环一次.
                                                                                struct usb_descriptor_header **descriptors;

                                                                                switch (speed) {

                                                                                case USB_SPEED_HIGH: //
                                                                                    descriptors = f->hs_descriptors;
                                                                                    break;
                                                                                }

                                                                                
                                                                                status = usb_descriptor_fillbuf(next, len,
                                                                                    (const struct usb_descriptor_header **) descriptors);
                                                                                int usb_descriptor_fillbuf(void *buf, unsigned buflen,
                                                                                        const struct usb_descriptor_header **src)
                                                                                {
                                                                                    u8	*dest = buf;

                                                                                    /* fill buffer from src[] until null descriptor ptr */
                                                                                    for (; NULL != *src; src++) {
                                                                                        unsigned		len = (*src)->bLength;

                                                                                        memcpy(dest, *src, len);
                                                                                        buflen -= len;
                                                                                        dest += len;
                                                                                    }
                                                                                    return dest - (u8 *)buf;
                                                                                }

                                                                                len -= status;
                                                                                next += status;
                                                                            }

                                                                            len = next - buf;
                                                                            c->wTotalLength = cpu_to_le16(len);
                                                                            return len;
                                                                        }
                                                                    }
                                                                }
                                                                return -EINVAL;
                                                            }
                                                            if (value >= 0) { //
                                                                value = min(w_length, (u16) value);
                                                            }
                                                            break;
                                                        }
                                                        break;
                                                    }

                                                    /* respond with data transfer before status phase? */
                                                    if (value >= 0 && value != USB_GADGET_DELAYED_STATUS) {
                                                        req->length = value;
                                                        req->context = cdev;
                                                        req->zero = value < w_length;
                                                        value = composite_ep0_queue(cdev, req, GFP_ATOMIC);
                                                    }

                                                    /* device either stalls (value < 0) or reports success */
                                                    return value;
                                                }
                                                spin_lock(&udc->lock);
                                            }

                                            return retval;
                                        }
                                    }
                                }
                            }
                            break;
                        case 9:
        					case9_usba_control_irq(udc, &udc->usba_ep[i]);
                            static void case9_usba_control_irq(struct usba_udc *udc, struct usba_ep *ep)
                            {
                                struct usba_request *req;
                                u32 epstatus;
                                u32 epctrl;

                                epstatus = usba_ep_readl(ep, STA);
                                epctrl = usba_ep_readl(ep, CTL);

                                req = NULL;
                                if (!list_empty(&ep->queue)) {
                                    req = list_entry(ep->queue.next,
                                             struct usba_request, queue);
                                }

                                /* epctrl & USBA_TX_PK_RDY 值为1, 表示tx包准备ok时将产生中断. */
                                /* 这里表示tx传输包准备OK, 下一步就是进行传输. */
                                if ((epctrl & USBA_TX_PK_RDY) && !(epstatus & USBA_TX_PK_RDY)) {
                                    if (req->submitted) {
                                    }
                                    else {
                                        case1_submit_request(ep, req);
                                        static void case1_submit_request(struct usba_ep *ep, struct usba_request *req)
                                        {
                                            req->req.actual = 0;
                                            req->submitted = 1;

                                            if (req->using_dma) {

                                            } else {
                                                next_fifo_transaction(ep, req);
                                                static void next_fifo_transaction(struct usba_ep *ep, struct usba_request *req)
                                                {
                                                    unsigned int transaction_len;

                                                    transaction_len = req->req.length - req->req.actual;
                                                    req->last_transaction = 1;

                                                    memcpy_toio(ep->fifo, req->req.buf + req->req.actual, transaction_len); <tag39>
                                                    /* 表示ep->fifo已经写入数据, 可以进行数据传输. */
                                                    usba_ep_writel(ep, SET_STA, USBA_TX_PK_RDY);
                                                    req->req.actual += transaction_len;
                                                }
                                                if (req->last_transaction) {
                                                    //USBA_EPT_CTL_DIS
                                                    /* 关闭tx包准备OK, 和tx传输错误中断 */
                                                    usba_ep_writel(ep, CTL_DIS, USBA_TX_PK_RDY);
                                                    /* 使能 IN data 传输完成中断 */
                                                    usba_ep_writel(ep, CTL_ENB, USBA_TX_COMPLETE);
                                                }
                                            }
                                        }
                                    }

                                    if (req->last_transaction) {
                                        /* 关闭tx包准备OK, 和tx传输错误中断 */
                                        usba_ep_writel(ep, CTL_DIS, USBA_TX_PK_RDY);
                                        /* 使能 IN data 传输完成中断 */
                                        usba_ep_writel(ep, CTL_ENB, USBA_TX_COMPLETE);
                                    }
                                }

                                epstatus = usba_ep_readl(ep, STA);
                                epctrl = usba_ep_readl(ep, CTL);

                                req = NULL;
                                if (!list_empty(&ep->queue)) {
                                    req = list_entry(ep->queue.next,
                                             struct usba_request, queue);
                                }

                                if ((epstatus & epctrl) & USBA_TX_COMPLETE) {
                                    usba_ep_writel(ep, CLR_STA, USBA_TX_COMPLETE);

                                    switch (ep->state) {
                                    case DATA_STAGE_IN: 
                                        /* 使能 OUT data 接收中断 */
                                        usba_ep_writel(ep, CTL_ENB, USBA_RX_BK_RDY);
                                        /* 关闭 IN data 传输完成 中断 */
                                        usba_ep_writel(ep, CTL_DIS, USBA_TX_COMPLETE);
                                        ep->state = STATUS_STAGE_OUT;
                                        break;
                                    }
                                }
                                epstatus = usba_ep_readl(ep, STA);
                                epctrl = usba_ep_readl(ep, CTL);

                                req = NULL;
                                if (!list_empty(&ep->queue)) {
                                    req = list_entry(ep->queue.next,
                                             struct usba_request, queue);
                                }

                                if ((epstatus & epctrl) & USBA_RX_BK_RDY) {
                                    switch (ep->state) {
                                    case STATUS_STAGE_OUT: 
                                        /* 清除 UDPHS_EPTSTAx 寄存器中的 RXRDY_TXKL 标志位 */
                                        usba_ep_writel(ep, CLR_STA, USBA_RX_BK_RDY);
                                        /* 关闭 OUT data 接收完成中断 */
                                        usba_ep_writel(ep, CTL_DIS, USBA_RX_BK_RDY);

                                        if (req) {
                                            list_del_init(&req->queue);
                                            //request_complete(ep, req, 0);
                                        }
                                        ep->state = WAIT_FOR_SETUP;
                                        break;
                                    }
                                }
                            }
                            break;
                        case 10:
        					case10_usba_control_irq(udc, &udc->usba_ep[i]);
                            static void case10_usba_control_irq(struct usba_udc *udc, struct usba_ep *ep)
                            {
                                struct usba_request *req;
                                u32 epstatus;
                                u32 epctrl;

                                epstatus = usba_ep_readl(ep, STA);
                                epctrl = usba_ep_readl(ep, CTL);

                                req = NULL;

                                if (epstatus & USBA_RX_SETUP) {
                                    union {
                                        struct usb_ctrlrequest crq;
                                        unsigned long data[2];
                                    } crq;
                                    unsigned int pkt_len;
                                    int ret;

                                    pkt_len = USBA_BFEXT(BYTE_COUNT, usba_ep_readl(ep, STA));

                                    memcpy_fromio(crq.data, ep->fifo, sizeof(crq));

                                    /* Free up one bank in the FIFO so that we can
                                     * generate or receive a reply right away. */
                                    usba_ep_writel(ep, CLR_STA, USBA_RX_SETUP);

                                    if (crq.crq.bRequestType & USB_DIR_IN) {
                                    } else {
                                        if (crq.crq.wLength != cpu_to_le16(0)) {
                                        }
                                        else {
                                            ep->state = STATUS_STAGE_IN;
                                        }
                                    }

                                    ret = -1;
                                    if (ep->index == 0) {
                                        ret = case10_handle_ep0_setup(udc, ep, &crq.crq);
                                        static int case10_handle_ep0_setup(struct usba_udc *udc, struct usba_ep *ep,
                                                struct usb_ctrlrequest *crq)
                                        {
                                            int retval = 0;

                                            switch (crq->bRequest) {
                                            default:
                                                spin_unlock(&udc->lock);
                                                /* composite_setup */
                                                retval = udc->driver->setup(&udc->gadget, crq);
                                                int composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
                                                {
                                                    struct usb_composite_dev	*cdev = get_gadget_data(gadget);
                                                    struct usb_request		*req = cdev->req;
                                                    int				value = -EOPNOTSUPP;
                                                    int				status = 0;
                                                    u16				w_index = le16_to_cpu(ctrl->wIndex);
                                                    u8				intf = w_index & 0xFF;
                                                    u16				w_value = le16_to_cpu(ctrl->wValue);
                                                    u16				w_length = le16_to_cpu(ctrl->wLength);
                                                    struct usb_function		*f = NULL;
                                                    u8				endp;

                                                    /* partial re-init of the response message; the function or the
                                                     * gadget might need to intercept e.g. a control-OUT completion
                                                     * when we delegate to it.
                                                     */
                                                    req->zero = 0;
                                                    req->context = cdev;
                                                    req->complete = composite_setup_complete;
                                                    req->length = 0;
                                                    gadget->ep0->driver_data = cdev;

                                                    switch (ctrl->bRequest) {
                                                    /* any number of configs can work */
                                                    case USB_REQ_SET_CONFIGURATION: //
                                                        spin_lock(&cdev->lock);
                                                        value = set_config(cdev, ctrl, w_value);
                                                        static int set_config(struct usb_composite_dev *cdev,
                                                                const struct usb_ctrlrequest *ctrl, unsigned number)
                                                        {
                                                            struct usb_gadget	*gadget = cdev->gadget;
                                                            struct usb_configuration *c = NULL;
                                                            int			result = -EINVAL;
                                                            unsigned		power = gadget_is_otg(gadget) ? 8 : 100;
                                                            int			tmp;

                                                            if (number) {
                                                                /* 找到匹配 索引值的 配置描述符 */
                                                                list_for_each_entry(c, &cdev->configs, list) {
                                                                    if (c->bConfigurationValue == number) {
                                                                        result = 0;
                                                                        break;
                                                                    }
                                                                }
                                                            }

                                                            INFO(cdev, "%s config #%d: %s\n",
                                                                 usb_speed_string(gadget->speed),
                                                                 number, c ? c->label : "unconfigured");

                                                            usb_gadget_set_state(gadget, USB_STATE_CONFIGURED);
                                                            void usb_gadget_set_state(struct usb_gadget *gadget,
                                                                    enum usb_device_state state)
                                                            {
                                                                gadget->state = state;
                                                                //schedule_work(&gadget->work);
                                                            }
                                                            cdev->config = c; <tag44>

                                                            /* Initialize all interfaces by setting them to altsetting zero. */
                                                            /* 找到该配置下的所有function内的端点描述符, 根据端点地址
                                                             * 设置位域function->endpoints 的值
                                                             * 遍历该config->interface[]数组下的所有接口描述符, 执行该接口的自定义初始化函数.
                                                             * 该函数由usb gadget设备驱动编写定义, 即用户自定义.*/
                                                            for (tmp = 0; tmp < MAX_CONFIG_INTERFACES; tmp++) {
                                                            pr_err("joker %s:in %d. tmp %d\n",__func__,__LINE__, tmp); //0 ,1
                                                                struct usb_function	*f = c->interface[tmp];
                                                                struct usb_descriptor_header **descriptors;

                                                                if (!f) {
                                                            pr_err("joker %s:in %d. tmp %d\n",__func__,__LINE__, tmp);  //1
                                                                    break;
                                                                }

                                                                /*
                                                                 * Record which endpoints are used by the function. This is used
                                                                 * to dispatch control requests targeted at that endpoint to the
                                                                 * function's setup callback instead of the current
                                                                 * configuration's setup callback.
                                                                 */
                                                                switch (gadget->speed) {
                                                                case USB_SPEED_HIGH://
                                                            pr_err("joker %s:in %d. tmp %d\n",__func__,__LINE__, tmp);  //0
                                                                    descriptors = f->hs_descriptors;
                                                                    break;
                                                                }

                                                                int i =0;
                                                                for (; *descriptors; ++descriptors, i++) {
                                                                    struct usb_endpoint_descriptor *ep;
                                                                    int addr;

                                                                    if ((*descriptors)->bDescriptorType != USB_DT_ENDPOINT) { //
                                                            pr_err("joker %s:in %d. tmp %d i %d\n",__func__,__LINE__, tmp, i); //tmp 0  i 0
                                                                        continue;
                                                                    }

                                                                    ep = (struct usb_endpoint_descriptor *)*descriptors;
                                                                    addr = ((ep->bEndpointAddress & 0x80) >> 3)|(ep->bEndpointAddress & 0x0f);
                                                                    /* 通过位域值 表示哪个端点被使用了.该func 拥有俩个端点. */
                                                                    set_bit(addr, f->endpoints); <tag45>
                                                            pr_err("joker %s:in %d. tmp %d i %d\n",__func__,__LINE__, tmp, i); //tmp 0, i 1,2
                                                                }

                                                            pr_err("joker %s:in %d. tmp %d\n",__func__,__LINE__, tmp);  //0
                                                                /* loopback_set_alt*/
                                                                result = f->set_alt(f, tmp, 0);
                                                                static int loopback_set_alt(struct usb_function *f,
                                                                        unsigned intf, unsigned alt)
                                                                {
                                                                    struct f_loopback	*loop = func_to_loop(f);
                                                                    struct usb_composite_dev *cdev = f->config->cdev;

                                                                    enable_endpoint(cdev, loop, loop->in_ep);
                                                                    enable_endpoint(cdev, loop, loop->out_ep);
                                                                    static int enable_endpoint(struct usb_composite_dev *cdev,
                                                                                   struct f_loopback *loop, struct usb_ep *ep)
                                                                    {
                                                                        int	result;

                                                                        result = config_ep_by_speed(cdev->gadget, &(loop->function), ep);
                                                                        int config_ep_by_speed(struct usb_gadget *g,
                                                                                    struct usb_function *f,
                                                                                    struct usb_ep *_ep)
                                                                        {
                                                                            struct usb_composite_dev	*cdev = get_gadget_data(g);
                                                                            struct usb_endpoint_descriptor *chosen_desc = NULL;
                                                                            struct usb_descriptor_header **speed_desc = NULL;

                                                                            struct usb_ss_ep_comp_descriptor *comp_desc = NULL;
                                                                            int want_comp_desc = 0;

                                                                            struct usb_descriptor_header **d_spd; /* cursor for speed desc */

                                                                            /* select desired speed */
                                                                            switch (g->speed) {
                                                                            case USB_SPEED_HIGH:
                                                                                if (gadget_is_dualspeed(g)) {
                                                                                    speed_desc = f->hs_descriptors;
                                                                                    break;
                                                                                }
                                                                            }
                                                                            /* find descriptors */
                                                                            int i = 0;
                                                                            for_each_ep_desc(speed_desc, d_spd) {
                                                                                i++;
                                                                                chosen_desc = (struct usb_endpoint_descriptor *)*d_spd;
                                                                                if (chosen_desc->bEndpointAddress == _ep->address) {
                                                                                pr_err("joker %s:in %d.i %d\n",__func__,__LINE__, i);
                                                                                                                    //in_ep 1, //out_ep 2
                                                                                    goto ep_found;
                                                                                }
                                                                            }

                                                                        ep_found:
                                                                            /* commit results */
                                                                            _ep->maxpacket = usb_endpoint_maxp(chosen_desc); <tag47>
                                                                            static inline int usb_endpoint_maxp(
                                                                                            const struct usb_endpoint_descriptor *epd)
                                                                            {
                                                                                return __le16_to_cpu(epd->wMaxPacketSize);
                                                                            }
                                                                            _ep->desc = chosen_desc; <tag46>
                                                                            _ep->comp_desc = NULL;
                                                                            _ep->maxburst = 0;
                                                                            _ep->mult = 0;
                                                                            if (!want_comp_desc) { //
                                                                                return 0;
                                                                            }
                                                                        }

                                                                        result = usb_ep_enable(ep);
                                                                        static inline int usb_ep_enable(struct usb_ep *ep)
                                                                        {
                                                                            int ret;

                                                                            /* usba_ep_enable */
                                                                            ret = ep->ops->enable(ep, ep->desc);
                                                                            static int
                                                                            usba_ep_enable(struct usb_ep *_ep,
                                                                                        const struct usb_endpoint_descriptor *desc)
                                                                            {
                                                                                struct usba_ep *ep = to_usba_ep(_ep);
                                                                                struct usba_udc *udc = ep->udc;
                                                                                unsigned long flags, ept_cfg, maxpacket;
                                                                                unsigned int nr_trans;

                                                                                maxpacket = usb_endpoint_maxp(desc) & 0x7ff;

                                                                                ep->is_isoc = 0;
                                                                                ep->is_in = 0;

                                                                                if (maxpacket <= 8) {
                                                                                }
                                                                                else { //
                                                                                    /* LSB is bit 1, not 0 */
                                                                                    ept_cfg = USBA_BF(EPT_SIZE, fls(maxpacket - 1) - 3);
                                                                                }

                                                                                DBG(DBG_HW, "%s: EPT_SIZE = %lu (maxpacket = %lu)\n",
                                                                                        ep->ep.name, ept_cfg, maxpacket);

                                                                                if (usb_endpoint_dir_in(desc)) { // in_ep
                                                                                    ep->is_in = 1;
                                                                                    ept_cfg |= USBA_EPT_DIR_IN;
                                                                                }

                                                                                switch (usb_endpoint_type(desc)) {
                                                                                case USB_ENDPOINT_XFER_BULK: //
                                                                                    ept_cfg |= USBA_BF(EPT_TYPE, USBA_EPT_TYPE_BULK);
                                                                                    ept_cfg |= USBA_BF(BK_NUMBER, USBA_BK_NUMBER_DOUBLE);
                                                                                    break;
                                                                                }

                                                                                spin_lock_irqsave(&ep->udc->lock, flags);

                                                                                //ep->ep.desc = desc;
                                                                                //ep->ep.maxpacket = maxpacket;
                                                                                
                                                                                /* ept_cfg:  0xab 0xa3 */
                                                                                /* 0xab:
                                                                                 * 最大包大小: 64字节
                                                                                 * 输入端点
                                                                                 * 批量端点
                                                                                 * Double bank (Ping-Pong: bank0/bank1)
                                                                                 * */
                                                                                /* 0xa3:
                                                                                 * 最大包大小: 64字节
                                                                                 * 输出端点
                                                                                 * 批量端点
                                                                                 * Double bank (Ping-Pong: bank0/bank1)
                                                                                 * */
                                                                                usba_ep_writel(ep, CFG, ept_cfg);
                                                                                /* 使能端点, 根据寄存器内的配置 */
                                                                                usba_ep_writel(ep, CTL_ENB, USBA_EPT_ENABLE);

                                                                                if (ep->can_dma) {
                                                                                    u32 ctrl;

                                                                                    /* in_ep: 0x2000352 
                                                                                     * out_ep: 0x6000752 */
                                                                                    /* 使用16个端点里的, 1号端点和2号端点, 0号是控制端点. */
                                                                              	    pr_err("joker %s:in %d. ep index %d\n",
                                                                                                        __func__,__LINE__, ep->index);
                                                                                    /* 使能1号2号端点的中断和 对应DMA通道的中断 */
                                                                                    usba_int_enb_set(udc, usba_int_enb_get(udc) |
                                                                                                  USBA_BF(EPT_INT, 1 << ep->index) |
                                                                                                  USBA_BF(DMA_INT, 1 << ep->index));
                                                                                    static inline void usba_int_enb_set(
                                                                                                    struct usba_udc *udc, u32 val)
                                                                                    {
                                                                                        usba_writel(udc, INT_ENB, val);
                                                                                        /* 保存中断寄存器的值 */
                                                                                        udc->int_enb_cache = val;
                                                                                    }
                                                                                    /* USBA_AUTO_VALID:
                                                                                     *   Enable this bit to automatically 
                                                                                     *   validate the current packet 
                                                                                     *   and switch to the next bank for 
                                                                                     *   both IN and OUT transfers.*/

                                                                                    /* USBA_INTDIS_DMA: 
                                                                                     *  If set, when an enabled endpoint-originated 
                                                                                     *  interrupt is triggered, the DMA request is disabled.*/
                                                                                    ctrl = USBA_AUTO_VALID | USBA_INTDIS_DMA;
                                                                                    usba_ep_writel(ep, CTL_ENB, ctrl);
                                                                                }

                                                                                spin_unlock_irqrestore(&udc->lock, flags);

                                                                                return 0;
                                                                            }

                                                                            ep->enabled = true;

                                                                            return 0;
                                                                        }
                                                                        ep->driver_data = loop;
                                                                        result = 0;

                                                                        return result;
                                                                    }

                                                                    /* 给端点分配任务. */
                                                                    alloc_requests(cdev, loop);
                                                                    static int alloc_requests(struct usb_composite_dev *cdev,
                                                                                  struct f_loopback *loop)
                                                                    {
                                                                        struct usb_request *in_req, *out_req;
                                                                        int result = 0;

                                                                        /*
                                                                         * allocate a bunch of read buffers and queue them all at once.
                                                                         * we buffer at most 'qlen' transfers; We allocate buffers only
                                                                         * for out transfer and reuse them in IN transfers to implement
                                                                         * our loopback functionality
                                                                         */
                                                                        in_req = usb_ep_alloc_request(loop->in_ep, GFP_ATOMIC);
                                                                        static inline struct usb_request *usb_ep_alloc_request(
                                                                                               struct usb_ep *ep, gfp_t gfp_flags)
                                                                        {
                                                                            /* usba_ep_alloc_request */
                                                                            return ep->ops->alloc_request(ep, gfp_flags);
                                                                            static struct usb_request *
                                                                            usba_ep_alloc_request(struct usb_ep *_ep, gfp_t gfp_flags)
                                                                            {
                                                                                struct usba_request *req;

                                                                                req = kzalloc(sizeof(*req), gfp_flags); <tag48>

                                                                                INIT_LIST_HEAD(&req->queue);

                                                                                return &req->req;
                                                                            }
                                                                        }
                                                                        out_req = alloc_ep_req(loop->out_ep, 0, loop->buflen);
                                                                        struct usb_request *alloc_ep_req(struct usb_ep *ep,
                                                                                                int len, int default_len)
                                                                        {
                                                                            struct usb_request      *req;

                                                                            req = usb_ep_alloc_request(ep, GFP_ATOMIC);
                                                                            static inline struct usb_request *usb_ep_alloc_request(
                                                                                                   struct usb_ep *ep, gfp_t gfp_flags)
                                                                            {
                                                                                /* usba_ep_alloc_request */
                                                                                return ep->ops->alloc_request(ep, gfp_flags);
                                                                                static struct usb_request *
                                                                                usba_ep_alloc_request(struct usb_ep *_ep, gfp_t gfp_flags)
                                                                                {
                                                                                    struct usba_request *req;

                                                                                    req = kzalloc(sizeof(*req), gfp_flags); <tag49>

                                                                                    INIT_LIST_HEAD(&req->queue);

                                                                                    return &req->req;
                                                                                }
                                                                            }
                                                                            if (req) {
                                                                                req->length = len ?: default_len;
                                                                                req->buf = kmalloc(req->length, GFP_ATOMIC); <tag50>
                                                                            }
                                                                            return req;
                                                                        }

                                                                        /* 当任务加入 ep 的任务队列成功后(非执行成功, 执行成功会触发中断),
                                                                         * 执行loopback_complete,
                                                                         * 当该任务经由usb设备控制器处理完成时, 会触发中断,
                                                                         * 执行ep队列的下一个任务.*/
                                                                        in_req->complete = loopback_complete;
                                                                        out_req->complete = loopback_complete;

                                                                        in_req->buf = out_req->buf; <tag51>
                                                                        /* length will be set in complete routine */
                                                                        in_req->context = out_req;
                                                                        out_req->context = in_req;

                                                                        /* 将out_req任务, 加入loop->out_ep的任务队列, 
                                                                         * 符合先进先处理原则.*/
                                                                        result = usb_ep_queue(loop->out_ep, out_req, GFP_ATOMIC);
                                                                        static inline int usb_ep_queue(struct usb_ep *ep,
                                                                                           struct usb_request *req, gfp_t gfp_flags)
                                                                        {
                                                                            /* usba_ep_queue */
                                                                            return ep->ops->queue(ep, req, gfp_flags);
                                                                            static int usba_ep_queue(struct usb_ep *_ep,
                                                                                        struct usb_request *_req, gfp_t gfp_flags)
                                                                            {
                                                                                struct usba_request *req = to_usba_req(_req);
                                                                                struct usba_ep *ep = to_usba_ep(_ep);
                                                                                struct usba_udc *udc = ep->udc;
                                                                                unsigned long flags;
                                                                                int ret;

                                                                                req->submitted = 0;
                                                                                req->using_dma = 0;
                                                                                req->last_transaction = 0;

                                                                                _req->status = -EINPROGRESS;
                                                                                _req->actual = 0;

                                                                                if (ep->can_dma) { //
                                                                                    return queue_dma(udc, ep, req, gfp_flags);
                                                                                    static int queue_dma(struct usba_udc *udc,
                                                                                            struct usba_ep *ep,
                                                                                            struct usba_request *req, gfp_t gfp_flags)
                                                                                    {
                                                                                        unsigned long flags;
                                                                                        int ret;

                                                                                        DBG(DBG_DMA, "%s: req l/%u d/%pad %c%c%c\n",
                                                                                            ep->ep.name, req->req.length, &req->req.dma,
                                                                                            req->req.zero ? 'Z' : 'z',
                                                                                            req->req.short_not_ok ? 'S' : 's',
                                                                                            req->req.no_interrupt ? 'I' : 'i');

                                                                                        ret = usb_gadget_map_request(&udc->gadget,
                                                                                                            &req->req, ep->is_in);
                                                                                        int usb_gadget_map_request(
                                                                                                struct usb_gadget *gadget,
                                                                                                struct usb_request *req, int is_in)
                                                                                        {
                                                                                            struct device *dev = gadget->dev.parent;

                                                                                            if (req->num_sgs) {
                                                                                            } else { 
                                                                                                req->dma = dma_map_single(dev,
                                                                                                        req->buf, req->length,
                                                                                                        is_in ? DMA_TO_DEVICE
                                                                                                                        : DMA_FROM_DEVICE);
                                                                                            }

                                                                                            return 0;
                                                                                        }

                                                                                        req->using_dma = 1;
                                                                                        /* req.length 设置 dma buf 大小
                                                                                         * USBA_DMA_CH_EN  使能该DMA通道
                                                                                         * USBA_DMA_END_BUF_IE  data 全部传输完成会产生中断
                                                                                         * USBA_DMA_END_BUF_EN  */
                                                                                        req->ctrl = USBA_BF(DMA_BUF_LEN, req->req.length)
                                                                                                | USBA_DMA_CH_EN | USBA_DMA_END_BUF_IE
                                                                                                | USBA_DMA_END_BUF_EN;

                                                                                        /* USBA_DMA_END_TR_IE 数据传输完成时产生中断 */
                                                                                        if (!ep->is_in) { //in_ep
                                                                                            req->ctrl |= USBA_DMA_END_TR_EN
                                                                                                            | USBA_DMA_END_TR_IE;
                                                                                        }

                                                                                        /*
                                                                                         * Add this request to the queue and submit for DMA if
                                                                                         * possible. Check if we're still alive first -- 
                                                                                         * we may have
                                                                                         * received a reset since last time we checked.
                                                                                         */
                                                                                        ret = -ESHUTDOWN;
                                                                                        spin_lock_irqsave(&udc->lock, flags);
                                                                                        if (ep->ep.desc) {
                                                                                            if (list_empty(&ep->queue)) { //
                                                                                                submit_request(ep, req);
                                                                                                static void submit_request(struct usba_ep *ep,
                                                                                                                    struct usba_request *req)
                                                                                                {
                                                                                                    req->req.actual = 0;
                                                                                                    req->submitted = 1;

                                                                                                    if (req->using_dma) {
                                                                                                        if (req->req.zero) {
                                                                                                            /* 需要发送0长包 */
                                                                                                            usba_ep_writel(ep, CTL_ENB,
                                                                                                                        USBA_SHORT_PACKET);
                                                                                                        }
                                                                                                        /* dma地址写入寄存器 */
                                                                                                        usba_dma_writel(ep, ADDRESS,
                                                                                                                            req->req.dma);
                                                                                                        usba_dma_writel(ep, CONTROL,
                                                                                                                            req->ctrl);
                                                                                        #define usba_dma_writel(ep, reg, value)				\
                                                                                           	usba_io_writel((value),
                                                                                                    (ep)->dma_regs + USBA_DMA_##reg)
                                                                                                    }
                                                                                                }
                                                                                            }

                                                                                            list_add_tail(&req->queue, &ep->queue);
                                                                                            ret = 0;
                                                                                        }
                                                                                        spin_unlock_irqrestore(&udc->lock, flags);

                                                                                        return ret;
                                                                                    }
                                                                                }
                                                                             }
                                                                        }

                                                                        return 0;
                                                                    }

                                                                    return 0;
                                                                }
                                                            }

                                                            /* when we return, be sure our power usage is valid */
                                                            power = c->MaxPower ? c->MaxPower : CONFIG_USB_GADGET_VBUS_DRAW; /*2mA*/
                                                        done:
                                                            //usb_gadget_vbus_draw(gadget, power);

                                                            return result;
                                                        }
                                                        spin_unlock(&cdev->lock);
                                                        break;
                                                    }

                                                    /* respond with data transfer before status phase? */
                                                    if (value >= 0 && value != USB_GADGET_DELAYED_STATUS) {
                                                        req->length = value;
                                                        req->context = cdev;
                                                        req->zero = value < w_length;
                                                        value = composite_ep0_queue(cdev, req, GFP_ATOMIC);
                                                        static int composite_ep0_queue(struct usb_composite_dev *cdev,
                                                                struct usb_request *req, gfp_t gfp_flags)
                                                        {
                                                            int ret;

                                                            ret = usb_ep_queue(cdev->gadget->ep0, req, gfp_flags);
                                                            static inline int usb_ep_queue(struct usb_ep *ep,
                                                                               struct usb_request *req, gfp_t gfp_flags)
                                                            {
                                                                /* usba_ep_queue */
                                                                return ep->ops->queue(ep, req, gfp_flags);
                                                                static int
                                                                usba_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
                                                                {
                                                                    struct usba_request *req = to_usba_req(_req);
                                                                    struct usba_ep *ep = to_usba_ep(_ep);
                                                                    struct usba_udc *udc = ep->udc;
                                                                    unsigned long flags;
                                                                    int ret;

                                                                    req->submitted = 0;
                                                                    req->using_dma = 0;
                                                                    req->last_transaction = 0;

                                                                    _req->status = -EINPROGRESS;
                                                                    _req->actual = 0;

                                                                    /* May have received a reset since last time we checked */
                                                                    ret = -ESHUTDOWN;
                                                                    spin_lock_irqsave(&udc->lock, flags);
                                                                    if (ep->ep.desc) { //
                                                                        list_add_tail(&req->queue, &ep->queue);

                                                                        if ((!ep_is_control(ep) && ep->is_in) ||
                                                                            (ep_is_control(ep)
                                                                                && (ep->state == DATA_STAGE_IN
                                                                                    || ep->state == STATUS_STAGE_IN))) { //
                                                                            /* 使能tx包准备ok,和tx传输错误中断. */
                                                                            usba_ep_writel(ep, CTL_ENB, USBA_TX_PK_RDY);
                                                                        }
                                                                        ret = 0;
                                                                    }
                                                                    spin_unlock_irqrestore(&udc->lock, flags);

                                                                    return ret;
                                                                }
                                                            }
                                                            if (ret == 0) {
                                                                if (cdev->req == req) {
                                                                    cdev->setup_pending = true;
                                                                }
                                                            }

                                                            return ret;
                                                        }
                                                    }

                                                    /* device either stalls (value < 0) or reports success */
                                                    return value;
                                                }
                                                spin_lock(&udc->lock);
                                            }

                                            return retval;
                                        }
                                    }
                                }
                            }
                            break;
                        case 11:
        					case11_usba_control_irq(udc, &udc->usba_ep[i]);
                            static void case11_usba_control_irq(struct usba_udc *udc, struct usba_ep *ep)
                            {
                                struct usba_request *req;
                                u32 epstatus;
                                u32 epctrl;

                                epstatus = usba_ep_readl(ep, STA);
                                epctrl = usba_ep_readl(ep, CTL);

                                req = NULL;
                                if (!list_empty(&ep->queue)) {
                                    req = list_entry(ep->queue.next,
                                             struct usba_request, queue);
                                }

                                if ((epctrl & USBA_TX_PK_RDY) && !(epstatus & USBA_TX_PK_RDY)) {
                                    if (req->submitted) {
                                    }
                                    else {
                                        case1_submit_request(ep, req);
                                        static void case1_submit_request(struct usba_ep *ep, struct usba_request *req)
                                        {
                                            req->req.actual = 0;
                                            req->submitted = 1;

                                            if (req->using_dma) {

                                            } else {
                                                next_fifo_transaction(ep, req);
                                                static void next_fifo_transaction(struct usba_ep *ep, struct usba_request *req)
                                                {
                                                    unsigned int transaction_len;

                                                    transaction_len = req->req.length - req->req.actual;
                                                    req->last_transaction = 1;

                                                    memcpy_toio(ep->fifo, req->req.buf + req->req.actual, transaction_len); <tag39>
                                                    /* 表示ep->fifo已经写入数据, 可以进行数据传输. */
                                                    usba_ep_writel(ep, SET_STA, USBA_TX_PK_RDY);
                                                    req->req.actual += transaction_len;
                                                }
                                                if (req->last_transaction) {
                                                    /* 关闭tx包准备OK, 和tx传输错误中断 */
                                                    usba_ep_writel(ep, CTL_DIS, USBA_TX_PK_RDY);
                                                    /* 使能 IN data 传输完成中断 */
                                                    usba_ep_writel(ep, CTL_ENB, USBA_TX_COMPLETE);
                                                }
                                            }
                                        }
                                    }

                                    if (req->last_transaction) {
                                        /* 关闭tx包准备OK, 和tx传输错误中断 */
                                        usba_ep_writel(ep, CTL_DIS, USBA_TX_PK_RDY);
                                        /* 使能 IN data 传输完成中断 */
                                        usba_ep_writel(ep, CTL_ENB, USBA_TX_COMPLETE);
                                    }
                                }
                                epstatus = usba_ep_readl(ep, STA);
                                epctrl = usba_ep_readl(ep, CTL);

                                req = NULL;
                                if (!list_empty(&ep->queue)) {
                                    req = list_entry(ep->queue.next,
                                             struct usba_request, queue);
                                }

                                if ((epstatus & epctrl) & USBA_TX_COMPLETE) {
                                    usba_ep_writel(ep, CLR_STA, USBA_TX_COMPLETE);

                                    switch (ep->state) {
                                    case STATUS_STAGE_IN: 
                                        if (req) {
                                            list_del_init(&req->queue);
                                            //request_complete(ep, req, 0);
                                            //submit_next_request(ep);
                                        }
                                        usba_ep_writel(ep, CTL_DIS, USBA_TX_COMPLETE);
                                        ep->state = WAIT_FOR_SETUP;
                                        break;
                                    }
                                }

                            }
                            break;
                        default:
    	                    pr_err("joker %s:in %d. ep_status case default\n",__func__,__LINE__);
        					usba_control_irq(udc, &udc->usba_ep[i]);
                    }
                    ep0_use_count++;
                }
			}
	}

    /* reset 完成时, 引发中断. */
	if (status & USBA_END_OF_RESET) {
		struct usba_ep *ep0;

        /* 写1, 清除INT_STA寄存器的中断标志位 */
		usba_writel(udc, INT_CLR, USBA_END_OF_RESET);
        #define USBA_END_OF_RESET			(1 <<  4)
        #define usba_writel(udc, reg, value)				\
        	usba_io_writel((value), (udc)->regs + USBA_##reg)
		//generate_bias_pulse(udc);
		//reset_all_endpoints(udc);

		if (udc->gadget.speed != USB_SPEED_UNKNOWN && udc->driver) {//
			udc->gadget.speed = USB_SPEED_UNKNOWN;
			spin_unlock(&udc->lock);
			usb_gadget_udc_reset(&udc->gadget, udc->driver);
            void usb_gadget_udc_reset(struct usb_gadget *gadget,
                    struct usb_gadget_driver *driver)
            {
                /* composite_disconnect */
                driver->reset(gadget);
                void composite_disconnect(struct usb_gadget *gadget)
                {
                    struct usb_composite_dev	*cdev = get_gadget_data(gadget);
                    unsigned long			flags;

                    /* REVISIT:  should we have config and device level
                     * disconnect callbacks?
                     */
                    spin_lock_irqsave(&cdev->lock, flags);
                    spin_unlock_irqrestore(&cdev->lock, flags);
                }
                usb_gadget_set_state(gadget, USB_STATE_DEFAULT);
                void usb_gadget_set_state(struct usb_gadget *gadget,
                        enum usb_device_state state)
                {
                    gadget->state = state;
                    //schedule_work(&gadget->work);
                }
            }
			spin_lock(&udc->lock);
		}

		if (status & USBA_HIGH_SPEED) { //
			udc->gadget.speed = USB_SPEED_HIGH;
        }
		else {
            /* 读取寄存器,知道当前控制器的运行速度. 并设置为满速. */
			udc->gadget.speed = USB_SPEED_FULL;
        }

		DBG(DBG_BUS, "%s bus reset detected\n",
		    usb_speed_string(udc->gadget.speed));

		ep0 = &udc->usba_ep[0];
		ep0->ep.desc = &usba_ep0_desc; <tag31>
		ep0->state = WAIT_FOR_SETUP;

        /* 设置ep0 属性:
         * 最大包大小: 64字节
         * 端点类型:   控制端点
         * bank编号:  bank 0*/
		usba_ep_writel(ep0, CFG,
				(USBA_BF(EPT_SIZE, EP0_EPT_SIZE)
				| USBA_BF(EPT_TYPE, USBA_EPT_TYPE_CONTROL)
				| USBA_BF(BK_NUMBER, USBA_BK_NUMBER_ONE)));

        /* 设置ep0:
         * USBA_EPT_ENABLE: 根据设备描述符 使能该端点
         * USBA_RX_SETUP: 使能 RX_SETUP 中断*/
		usba_ep_writel(ep0, CTL_ENB,
				USBA_EPT_ENABLE | USBA_RX_SETUP);

        #define usba_ep_writel(ep, reg, value)				\
        	usba_io_writel((value), (ep)->ep_regs + USBA_EPT_##reg)

        /* 写入 0x152 */
        /* USBA_DET_SUSPEND:  使能 suspend 中断
         * USBA_END_OF_RESUME: 使能 END of resume 中断. resume完成后引发中断.
         * EPT_0:  使能 ep0 中断
         * 使能 end of reset 中断.*/
		usba_int_enb_set(udc, int_enb | USBA_BF(EPT_INT, 1) | USBA_DET_SUSPEND | USBA_END_OF_RESUME);
        static inline void usba_int_enb_set(struct usba_udc *udc, u32 val)
        {
            usba_writel(udc, INT_ENB, val);
            /* int_enb 寄存器值的记录 */
            udc->int_enb_cache = val;
        }
	}

	spin_unlock(&udc->lock);

	return IRQ_HANDLED;
}

========old============
					usba_control_irq(udc, &udc->usba_ep[i]);
                    static void usba_control_irq(struct usba_udc *udc, struct usba_ep *ep)
                    {
                        struct usba_request *req;
                        u32 epstatus;
                        u32 epctrl;

                    restart:
                        epstatus = usba_ep_readl(ep, STA);
                        epctrl = usba_ep_readl(ep, CTL);

                        DBG(DBG_INT, "%s [%d]: s/%08x c/%08x\n",
                                ep->ep.name, ep->state, epstatus, epctrl);

                        req = NULL;
                        if (!list_empty(&ep->queue)) { //
                            req = list_entry(ep->queue.next, struct usba_request, queue);
                        }

                        if ((epctrl & USBA_TX_PK_RDY) && !(epstatus & USBA_TX_PK_RDY)) { //
                            if (req->submitted) {
                            }
                            else { //
                                submit_request(ep, req);
                                static void submit_request(struct usba_ep *ep, struct usba_request *req)
                                {
                                    DBG(DBG_QUEUE, "%s: submit_request: req %p (length %d)\n",
                                        ep->ep.name, req, req->req.length);

                                    req->req.actual = 0;
                                    req->submitted = 1;

                                    if (req->using_dma) { //

                                        if (req->req.zero) { //
                                            usba_ep_writel(ep, CTL_ENB, USBA_SHORT_PACKET);
                                        }
                                        else { //
                                            usba_ep_writel(ep, CTL_DIS, USBA_SHORT_PACKET);
                                        }

                                        usba_dma_writel(ep, ADDRESS, req->req.dma);
                                        usba_dma_writel(ep, CONTROL, req->ctrl);
                                    } else { //
                                        next_fifo_transaction(ep, req);
                                        static void next_fifo_transaction(struct usba_ep *ep, struct usba_request *req)
                                        {
                                            unsigned int transaction_len;

                                            transaction_len = req->req.length - req->req.actual;
                                            req->last_transaction = 1;

                                            DBG(DBG_QUEUE, "%s: submit_transaction, req %p (length %d)%s\n",
                                                ep->ep.name, req, transaction_len,
                                                req->last_transaction ? ", done" : "");

                                            memcpy_toio(ep->fifo, req->req.buf + req->req.actual, transaction_len);
                                            usba_ep_writel(ep, SET_STA, USBA_TX_PK_RDY);
                                            req->req.actual += transaction_len;
                                        }
                                        if (req->last_transaction) { //
                                            usba_ep_writel(ep, CTL_DIS, USBA_TX_PK_RDY);
                                            usba_ep_writel(ep, CTL_ENB, USBA_TX_COMPLETE);
                                        }
                                    }
                                }
                            }

                            if (req->last_transaction) {//
                                usba_ep_writel(ep, CTL_DIS, USBA_TX_PK_RDY);
                                usba_ep_writel(ep, CTL_ENB, USBA_TX_COMPLETE);
                            }
                            goto restart;
                        }
                        if ((epstatus & epctrl) & USBA_TX_COMPLETE) { //
                            usba_ep_writel(ep, CLR_STA, USBA_TX_COMPLETE);

                            switch (ep->state) {
                            case DATA_STAGE_IN: //
                                usba_ep_writel(ep, CTL_ENB, USBA_RX_BK_RDY);
                                usba_ep_writel(ep, CTL_DIS, USBA_TX_COMPLETE);
                                ep->state = STATUS_STAGE_OUT;
                                break;
                            case STATUS_STAGE_ADDR: //
                                /* Activate our new address */
                                usba_writel(udc, CTRL, (usba_readl(udc, CTRL)
                                            | USBA_FADDR_EN));
                                usba_ep_writel(ep, CTL_DIS, USBA_TX_COMPLETE);
                                ep->state = WAIT_FOR_SETUP;
                                break;
                            case STATUS_STAGE_IN: //
                                if (req) { //
                                    list_del_init(&req->queue);
                                    //request_complete(ep, req, 0);
                                    //submit_next_request(ep);
                                }
                                usba_ep_writel(ep, CTL_DIS, USBA_TX_COMPLETE);
                                ep->state = WAIT_FOR_SETUP;
                                break;
                            }

                            goto restart;
                        }
                        if ((epstatus & epctrl) & USBA_RX_BK_RDY) { //
                            switch (ep->state) {
                            case STATUS_STAGE_OUT: //
                                usba_ep_writel(ep, CLR_STA, USBA_RX_BK_RDY);
                                usba_ep_writel(ep, CTL_DIS, USBA_RX_BK_RDY);

                                if (req) { //
                                    list_del_init(&req->queue);
                                    //request_complete(ep, req, 0);
                                }
                                ep->state = WAIT_FOR_SETUP;
                                break;
                            }

                            goto restart;
                        }
                        if (epstatus & USBA_RX_SETUP) { //
                            union {
                                struct usb_ctrlrequest crq;
                                unsigned long data[2];
                            } crq;
                            unsigned int pkt_len;
                            int ret;

                            pkt_len = USBA_BFEXT(BYTE_COUNT, usba_ep_readl(ep, STA));
                            DBG(DBG_HW, "Packet length: %u\n", pkt_len);

                            DBG(DBG_FIFO, "Copying ctrl request from 0x%p:\n", ep->fifo);
                            memcpy_fromio(crq.data, ep->fifo, sizeof(crq));

                            /* Free up one bank in the FIFO so that we can
                             * generate or receive a reply right away. */
                            usba_ep_writel(ep, CLR_STA, USBA_RX_SETUP);

                            /* printk(KERN_DEBUG "setup: %d: %02x.%02x\n",
                                ep->state, crq.crq.bRequestType,
                                crq.crq.bRequest); */

                            if (crq.crq.bRequestType & USB_DIR_IN) { //
                                /*
                                 * The USB 2.0 spec states that "if wLength is
                                 * zero, there is no data transfer phase."
                                 * However, testusb #14 seems to actually
                                 * expect a data phase even if wLength = 0...
                                 */
                                ep->state = DATA_STAGE_IN;
                            } else { //
                                if (crq.crq.wLength != cpu_to_le16(0)) {
                                }
                                else { //
                                    ep->state = STATUS_STAGE_IN;
                                }
                            }

                            ret = -1;
                            if (ep->index == 0) { //
                                ret = handle_ep0_setup(udc, ep, &crq.crq);
                                static int handle_ep0_setup(struct usba_udc *udc, struct usba_ep *ep,
                                        struct usb_ctrlrequest *crq)
                                {
                                    int retval = 0;

                                    switch (crq->bRequest) {
                                    case USB_REQ_SET_ADDRESS: //
                                        set_address(udc, le16_to_cpu(crq->wValue));
                                        static inline void set_address(struct usba_udc *udc, unsigned int addr)
                                        {
                                            u32 regval;

                                            regval = usba_readl(udc, CTRL);
                                            regval = USBA_BFINS(DEV_ADDR, addr, regval);
                                            usba_writel(udc, CTRL, regval);
                                        }
                                        send_status(udc, ep);
                                        static void send_status(struct usba_udc *udc, struct usba_ep *ep)
                                        {
                                            ep->state = STATUS_STAGE_IN;
                                            usba_ep_writel(ep, SET_STA, USBA_TX_PK_RDY);
                                            usba_ep_writel(ep, CTL_ENB, USBA_TX_COMPLETE);
                                        }
                                        ep->state = STATUS_STAGE_ADDR;
                                        break;

                                    default:
                                        spin_unlock(&udc->lock);
                                        /* composite_setup */
                                        retval = udc->driver->setup(&udc->gadget, crq);
                                        int composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
                                        {
                                            struct usb_composite_dev	*cdev = get_gadget_data(gadget);
                                            struct usb_request		*req = cdev->req;
                                            int				value = -EOPNOTSUPP;
                                            int				status = 0;
                                            u16				w_index = le16_to_cpu(ctrl->wIndex);
                                            u8				intf = w_index & 0xFF;
                                            u16				w_value = le16_to_cpu(ctrl->wValue);
                                            u16				w_length = le16_to_cpu(ctrl->wLength);
                                            struct usb_function		*f = NULL;
                                            u8				endp;

                                            /* partial re-init of the response message; the function or the
                                             * gadget might need to intercept e.g. a control-OUT completion
                                             * when we delegate to it.
                                             */
                                            req->zero = 0;
                                            req->context = cdev;
                                            req->complete = composite_setup_complete;
                                            req->length = 0;
                                            gadget->ep0->driver_data = cdev;

                                            switch (ctrl->bRequest) {

                                            /* we handle all standard USB descriptors */
                                            case USB_REQ_GET_DESCRIPTOR: //
                                                switch (w_value >> 8) {

                                                case USB_DT_DEVICE: //
                                                    cdev->desc.bNumConfigurations = count_configs(cdev, USB_DT_DEVICE);
                                                    static int count_configs(struct usb_composite_dev *cdev, unsigned type)
                                                    {
                                                        struct usb_gadget		*gadget = cdev->gadget;
                                                        struct usb_configuration	*c;
                                                        unsigned			count = 0;
                                                        int				hs = 0;
                                                        int				ss = 0;

                                                        if (gadget_is_dualspeed(gadget)) {
                                                            if (gadget->speed == USB_SPEED_HIGH) {
                                                                hs = 1;
                                                            }
                                                        }
                                                        list_for_each_entry(c, &cdev->configs, list) {
                                                            /* ignore configs that won't work at this speed */
                                                            if (hs) {
                                                            }
                                                            count++;
                                                        }
                                                        return count;
                                                    }
                                                    cdev->desc.bMaxPacketSize0 = cdev->gadget->ep0->maxpacket;
                                                    if (gadget_is_superspeed(gadget)) {
                                                    } else { //
                                                        cdev->desc.bcdUSB = cpu_to_le16(0x0200);
                                                    }

                                                    value = min(w_length, (u16) sizeof cdev->desc);
                                                    memcpy(req->buf, &cdev->desc, value);
                                                    break;
                                                case USB_DT_CONFIG: //
                                                    value = config_desc(cdev, w_value);
                                                    static int config_desc(struct usb_composite_dev *cdev, unsigned w_value)
                                                    {
                                                        struct usb_gadget		*gadget = cdev->gadget;
                                                        struct usb_configuration	*c;
                                                        struct list_head		*pos;
                                                        u8				type = w_value >> 8;
                                                        enum usb_device_speed		speed = USB_SPEED_UNKNOWN;

                                                        if (gadget_is_dualspeed(gadget)) {
                                                            int	hs = 0;
                                                            if (gadget->speed == USB_SPEED_HIGH) { //
                                                                hs = 1;
                                                            }

                                                            if (hs) {//
                                                                speed = USB_SPEED_HIGH;
                                                            }

                                                        }

                                                        /* This is a lookup by config *INDEX* */
                                                        w_value &= 0xff;

                                                        pos = &cdev->configs;
                                                        c = cdev->os_desc_config;

                                                        pos = pos->next;
                                                        {
                                                            c = list_entry(pos, typeof(*c), list);

                                                            if (w_value == 0) { //
                                                                return config_buf(c, speed, cdev->req->buf, type);
                                                                static int config_buf(struct usb_configuration *config,
                                                                        enum usb_device_speed speed, void *buf, u8 type)
                                                                {
                                                                    struct usb_config_descriptor	*c = buf;
                                                                    void				*next = buf + USB_DT_CONFIG_SIZE;
                                                                    int				len;
                                                                    struct usb_function		*f;
                                                                    int				status;

                                                                    len = USB_COMP_EP0_BUFSIZ - USB_DT_CONFIG_SIZE;
                                                                    /* write the config descriptor */
                                                                    c = buf;
                                                                    c->bLength = USB_DT_CONFIG_SIZE;
                                                                    c->bDescriptorType = type;
                                                                    /* wTotalLength is written later */
                                                                    c->bNumInterfaces = config->next_interface_id;
                                                                    c->bConfigurationValue = config->bConfigurationValue;
                                                                    c->iConfiguration = config->iConfiguration;
                                                                    c->bmAttributes = USB_CONFIG_ATT_ONE | config->bmAttributes;
                                                                    c->bMaxPower = encode_bMaxPower(speed, config);
                                                                    static u8 encode_bMaxPower(enum usb_device_speed speed,
                                                                            struct usb_configuration *c)
                                                                    {
                                                                        unsigned val;

                                                                        if (c->MaxPower) {
                                                                        }
                                                                        else { //
                                                                            val = CONFIG_USB_GADGET_VBUS_DRAW;
                                                                        }

                                                                        switch (speed) {
                                                                        default: //
                                                                            return DIV_ROUND_UP(val, 2);
                                                                        }
                                                                    }

                                                                    /* add each function's descriptors */
                                                                    list_for_each_entry(f, &config->functions, list) { // 循环一次.
                                                                        struct usb_descriptor_header **descriptors;

                                                                        switch (speed) {

                                                                        case USB_SPEED_HIGH: //
                                                                            descriptors = f->hs_descriptors;
                                                                            break;
                                                                        }

                                                                        
                                                                        status = usb_descriptor_fillbuf(next, len,
                                                                            (const struct usb_descriptor_header **) descriptors);
                                                                        int usb_descriptor_fillbuf(void *buf, unsigned buflen,
                                                                                const struct usb_descriptor_header **src)
                                                                        {
                                                                            u8	*dest = buf;

                                                                            /* fill buffer from src[] until null descriptor ptr */
                                                                            for (; NULL != *src; src++) {
                                                                                unsigned		len = (*src)->bLength;

                                                                                memcpy(dest, *src, len);
                                                                                buflen -= len;
                                                                                dest += len;
                                                                            }
                                                                            return dest - (u8 *)buf;
                                                                        }

                                                                        len -= status;
                                                                        next += status;
                                                                    }

                                                                    len = next - buf;
                                                                    c->wTotalLength = cpu_to_le16(len);
                                                                    return len;
                                                                }
                                                            }
                                                        }
                                                        return -EINVAL;
                                                    }
                                                    if (value >= 0) { //
                                                        value = min(w_length, (u16) value);
                                                    }
                                                    break;
                                                }
                                                break;

                                            /* any number of configs can work */
                                            case USB_REQ_SET_CONFIGURATION: //
                                                spin_lock(&cdev->lock);
                                                value = set_config(cdev, ctrl, w_value);
                                                static int set_config(struct usb_composite_dev *cdev,
                                                        const struct usb_ctrlrequest *ctrl, unsigned number)
                                                {
                                                    struct usb_gadget	*gadget = cdev->gadget;
                                                    struct usb_configuration *c = NULL;
                                                    int			result = -EINVAL;
                                                    unsigned		power = gadget_is_otg(gadget) ? 8 : 100;
                                                    int			tmp;

                                                    if (number) { //
                                                        list_for_each_entry(c, &cdev->configs, list) {
                                                            if (c->bConfigurationValue == number) { //
                                                                result = 0;
                                                                break;
                                                            }
                                                        }
                                                    }

                                                    usb_gadget_set_state(gadget, USB_STATE_CONFIGURED);
                                                    cdev->config = c;

                                                    /* Initialize all interfaces by setting them to altsetting zero. */
                                                    for (tmp = 0; tmp < MAX_CONFIG_INTERFACES; tmp++) {
                                                    pr_err("joker %s:in %d. tmp %d\n",__func__,__LINE__, tmp); //0 ,1
                                                        struct usb_function	*f = c->interface[tmp];
                                                        struct usb_descriptor_header **descriptors;

                                                        if (!f) {//
                                                    pr_err("joker %s:in %d. tmp %d\n",__func__,__LINE__, tmp);  //1
                                                            break;
                                                        }

                                                        /*
                                                         * Record which endpoints are used by the function. This is used
                                                         * to dispatch control requests targeted at that endpoint to the
                                                         * function's setup callback instead of the current
                                                         * configuration's setup callback.
                                                         */
                                                        switch (gadget->speed) {
                                                        case USB_SPEED_HIGH://
                                                    pr_err("joker %s:in %d. tmp %d\n",__func__,__LINE__, tmp);  //0
                                                            descriptors = f->hs_descriptors;
                                                            break;
                                                        }

                                                        int i =0;
                                                        for (; *descriptors; ++descriptors, i++) {
                                                            struct usb_endpoint_descriptor *ep;
                                                            int addr;

                                                            if ((*descriptors)->bDescriptorType != USB_DT_ENDPOINT) { //
                                                    pr_err("joker %s:in %d. tmp %d i %d\n",__func__,__LINE__, tmp, i); //tmp 0  i 0
                                                                continue;
                                                            }

                                                            ep = (struct usb_endpoint_descriptor *)*descriptors;
                                                            addr = ((ep->bEndpointAddress & 0x80) >> 3)
                                                                 |  (ep->bEndpointAddress & 0x0f);
                                                            set_bit(addr, f->endpoints);
                                                    pr_err("joker %s:in %d. tmp %d i %d\n",__func__,__LINE__, tmp, i); //tmp 0, i 1,2
                                                        }

                                                    pr_err("joker %s:in %d. tmp %d\n",__func__,__LINE__, tmp);  //0
                                                        /* loopback_set_alt*/
                                                        result = f->set_alt(f, tmp, 0);
                                                        static int loopback_set_alt(struct usb_function *f,
                                                                unsigned intf, unsigned alt)
                                                        {
                                                            struct f_loopback	*loop = func_to_loop(f);
                                                            struct usb_composite_dev *cdev = f->config->cdev;

                                                            enable_endpoint(cdev, loop, loop->in_ep);
                                                            enable_endpoint(cdev, loop, loop->out_ep);
                                                            static int enable_endpoint(struct usb_composite_dev *cdev,
                                                                           struct f_loopback *loop, struct usb_ep *ep)
                                                            {
                                                                int	result;

                                                                result = config_ep_by_speed(cdev->gadget, &(loop->function), ep);
                                                                int config_ep_by_speed(struct usb_gadget *g,
                                                                            struct usb_function *f,
                                                                            struct usb_ep *_ep)
                                                                {
                                                                    pr_err("joker %s:in %d.\n",__func__,__LINE__);
                                                                    struct usb_composite_dev	*cdev = get_gadget_data(g);
                                                                    struct usb_endpoint_descriptor *chosen_desc = NULL;
                                                                    struct usb_descriptor_header **speed_desc = NULL;

                                                                    struct usb_ss_ep_comp_descriptor *comp_desc = NULL;
                                                                    int want_comp_desc = 0;

                                                                    struct usb_descriptor_header **d_spd; /* cursor for speed desc */

                                                                    /* select desired speed */
                                                                    switch (g->speed) {
                                                                    case USB_SPEED_HIGH:
                                                                        if (gadget_is_dualspeed(g)) { //
                                                                            speed_desc = f->hs_descriptors;
                                                                            break;
                                                                        }
                                                                    }
                                                                    /* find descriptors */
                                                                    int i = 0;
                                                                    for_each_ep_desc(speed_desc, d_spd) {
                                                                        i++;
                                                                        chosen_desc = (struct usb_endpoint_descriptor *)*d_spd;
                                                                        if (chosen_desc->bEndpointAddress == _ep->address) {
                                                                        pr_err("joker %s:in %d.i %d\n",__func__,__LINE__, i);
                                                                                                            //in_ep 1, //out_ep 2
                                                                            goto ep_found;
                                                                        }
                                                                    }

                                                                ep_found:
                                                                    /* commit results */
                                                                    _ep->maxpacket = usb_endpoint_maxp(chosen_desc);
                                                                    static inline int usb_endpoint_maxp(
                                                                                    const struct usb_endpoint_descriptor *epd)
                                                                    {
                                                                        return __le16_to_cpu(epd->wMaxPacketSize);
                                                                    }
                                                                    _ep->desc = chosen_desc;
                                                                    _ep->comp_desc = NULL;
                                                                    _ep->maxburst = 0;
                                                                    _ep->mult = 0;
                                                                    if (!want_comp_desc) { //
                                                                        return 0;
                                                                    }
                                                                }

                                                                result = usb_ep_enable(ep);
                                                                static inline int usb_ep_enable(struct usb_ep *ep)
                                                                {
                                                                    int ret;

                                                                    /* usba_ep_enable */
                                                                    ret = ep->ops->enable(ep, ep->desc);
                                                                    static int
                                                                    usba_ep_enable(struct usb_ep *_ep,
                                                                                const struct usb_endpoint_descriptor *desc)
                                                                    {
                                                                        struct usba_ep *ep = to_usba_ep(_ep);
                                                                        struct usba_udc *udc = ep->udc;
                                                                        unsigned long flags, ept_cfg, maxpacket;
                                                                        unsigned int nr_trans;

                                                                        maxpacket = usb_endpoint_maxp(desc) & 0x7ff;

                                                                        ep->is_isoc = 0;
                                                                        ep->is_in = 0;

                                                                        if (maxpacket <= 8) {
                                                                        }
                                                                        else { //
                                                                            /* LSB is bit 1, not 0 */
                                                                            ept_cfg = USBA_BF(EPT_SIZE, fls(maxpacket - 1) - 3);
                                                                        }

                                                                        DBG(DBG_HW, "%s: EPT_SIZE = %lu (maxpacket = %lu)\n",
                                                                                ep->ep.name, ept_cfg, maxpacket);

                                                                        if (usb_endpoint_dir_in(desc)) { // in_ep
                                                                            ep->is_in = 1;
                                                                            ept_cfg |= USBA_EPT_DIR_IN;
                                                                        }

                                                                        switch (usb_endpoint_type(desc)) {
                                                                        case USB_ENDPOINT_XFER_BULK: //
                                                                            ept_cfg |= USBA_BF(EPT_TYPE, USBA_EPT_TYPE_BULK);
                                                                            ept_cfg |= USBA_BF(BK_NUMBER, USBA_BK_NUMBER_DOUBLE);
                                                                            break;
                                                                        }

                                                                        spin_lock_irqsave(&ep->udc->lock, flags);

                                                                        ep->ep.desc = desc;
                                                                        ep->ep.maxpacket = maxpacket;

                                                                        usba_ep_writel(ep, CFG, ept_cfg);
                                                                        usba_ep_writel(ep, CTL_ENB, USBA_EPT_ENABLE);

                                                                        if (ep->can_dma) { //
                                                                            u32 ctrl;

                                                                            usba_int_enb_set(udc, usba_int_enb_get(udc) |
                                                                                          USBA_BF(EPT_INT, 1 << ep->index) |
                                                                                          USBA_BF(DMA_INT, 1 << ep->index));
                                                                            static inline void usba_int_enb_set(
                                                                                            struct usba_udc *udc, u32 val)
                                                                            {
                                                                                usba_writel(udc, INT_ENB, val);
                                                                                udc->int_enb_cache = val;
                                                                            }
                                                                            ctrl = USBA_AUTO_VALID | USBA_INTDIS_DMA;
                                                                            usba_ep_writel(ep, CTL_ENB, ctrl);
                                                                        }

                                                                        spin_unlock_irqrestore(&udc->lock, flags);

                                                                        return 0;
                                                                    }

                                                                    ep->enabled = true;

                                                                    return 0;
                                                                }
                                                                ep->driver_data = loop;
                                                                result = 0;

                                                                return result;
                                                            }

                                                            /* 给端点分配任务. */
                                                            alloc_requests(cdev, loop);
                                                            static int alloc_requests(struct usb_composite_dev *cdev,
                                                                          struct f_loopback *loop)
                                                            {
                                                                pr_err("joker %s:in %d.\n",__func__,__LINE__);
                                                                struct usb_request *in_req, *out_req;
                                                                int result = 0;

                                                                /*
                                                                 * allocate a bunch of read buffers and queue them all at once.
                                                                 * we buffer at most 'qlen' transfers; We allocate buffers only
                                                                 * for out transfer and reuse them in IN transfers to implement
                                                                 * our loopback functionality
                                                                 */
                                                                in_req = usb_ep_alloc_request(loop->in_ep, GFP_ATOMIC);
                                                                static inline struct usb_request *usb_ep_alloc_request(
                                                                                       struct usb_ep *ep, gfp_t gfp_flags)
                                                                {
                                                                    /* usba_ep_alloc_request */
                                                                    return ep->ops->alloc_request(ep, gfp_flags);
                                                                    static struct usb_request *
                                                                    usba_ep_alloc_request(struct usb_ep *_ep, gfp_t gfp_flags)
                                                                    {
                                                                        struct usba_request *req;

                                                                        req = kzalloc(sizeof(*req), gfp_flags);

                                                                        INIT_LIST_HEAD(&req->queue);

                                                                        return &req->req;
                                                                    }
                                                                }
                                                                out_req = alloc_ep_req(loop->out_ep, 0, loop->buflen);
                                                                struct usb_request *alloc_ep_req(struct usb_ep *ep,
                                                                                        int len, int default_len)
                                                                {
                                                                    struct usb_request      *req;

                                                                    req = usb_ep_alloc_request(ep, GFP_ATOMIC);
                                                                    if (req) {
                                                                        req->length = len ?: default_len;
                                                                        req->buf = kmalloc(req->length, GFP_ATOMIC);
                                                                    }
                                                                    return req;
                                                                }

                                                                /* 当任务加入 ep 的任务队列成功后(非执行成功, 执行成功会触发中断),
                                                                 * 执行loopback_complete,
                                                                 * 当该任务经由usb设备控制器处理完成时, 会触发中断,
                                                                 * 执行ep队列的下一个任务.*/
                                                                in_req->complete = loopback_complete;
                                                                out_req->complete = loopback_complete;

                                                                in_req->buf = out_req->buf;
                                                                /* length will be set in complete routine */
                                                                in_req->context = out_req;
                                                                out_req->context = in_req;

                                                                /* 将out_req任务, 加入loop->out_ep的任务队列, 
                                                                 * 符合先进先处理原则.*/
                                                                result = usb_ep_queue(loop->out_ep, out_req, GFP_ATOMIC);
                                                                static inline int usb_ep_queue(struct usb_ep *ep,
                                                                                   struct usb_request *req, gfp_t gfp_flags)
                                                                {
                                                                    /* usba_ep_queue */
                                                                    return ep->ops->queue(ep, req, gfp_flags);
                                                                    static int
                                                                    usba_ep_queue(struct usb_ep *_ep,
                                                                                struct usb_request *_req, gfp_t gfp_flags)
                                                                    {
                                                                        struct usba_request *req = to_usba_req(_req);
                                                                        struct usba_ep *ep = to_usba_ep(_ep);
                                                                        struct usba_udc *udc = ep->udc;
                                                                        unsigned long flags;
                                                                        int ret;

                                                                        req->submitted = 0;
                                                                        req->using_dma = 0;
                                                                        req->last_transaction = 0;

                                                                        _req->status = -EINPROGRESS;
                                                                        _req->actual = 0;

                                                                        if (ep->can_dma) { //
                                                                            return queue_dma(udc, ep, req, gfp_flags);
                                                                            static int queue_dma(struct usba_udc *udc,
                                                                                    struct usba_ep *ep,
                                                                                    struct usba_request *req, gfp_t gfp_flags)
                                                                            {
                                                                                unsigned long flags;
                                                                                int ret;

                                                                                DBG(DBG_DMA, "%s: req l/%u d/%pad %c%c%c\n",
                                                                                    ep->ep.name, req->req.length, &req->req.dma,
                                                                                    req->req.zero ? 'Z' : 'z',
                                                                                    req->req.short_not_ok ? 'S' : 's',
                                                                                    req->req.no_interrupt ? 'I' : 'i');

                                                                                ret = usb_gadget_map_request(&udc->gadget,
                                                                                                    &req->req, ep->is_in);
                                                                                int usb_gadget_map_request(
                                                                                        struct usb_gadget *gadget,
                                                                                        struct usb_request *req, int is_in)
                                                                                {
                                                                                    struct device *dev = gadget->dev.parent;

                                                                                    if (req->num_sgs) {
                                                                                    } else { 
                                                                                        req->dma = dma_map_single(dev,
                                                                                                req->buf, req->length,
                                                                                                is_in ? DMA_TO_DEVICE
                                                                                                                : DMA_FROM_DEVICE);
                                                                                    }

                                                                                    return 0;
                                                                                }

                                                                                req->using_dma = 1;
                                                                                req->ctrl = USBA_BF(DMA_BUF_LEN, req->req.length)
                                                                                        | USBA_DMA_CH_EN | USBA_DMA_END_BUF_IE
                                                                                        | USBA_DMA_END_BUF_EN;

                                                                                if (!ep->is_in) { //in_ep
                                                                                    req->ctrl |= USBA_DMA_END_TR_EN
                                                                                                    | USBA_DMA_END_TR_IE;
                                                                                }

                                                                                /*
                                                                                 * Add this request to the queue and submit for DMA if
                                                                                 * possible. Check if we're still alive first -- we may have
                                                                                 * received a reset since last time we checked.
                                                                                 */
                                                                                ret = -ESHUTDOWN;
                                                                                spin_lock_irqsave(&udc->lock, flags);
                                                                                if (ep->ep.desc) {
                                                                                    if (list_empty(&ep->queue)) { //
                                                                                        submit_request(ep, req);
                                                                                    }

                                                                                    list_add_tail(&req->queue, &ep->queue);
                                                                                    ret = 0;
                                                                                }
                                                                                spin_unlock_irqrestore(&udc->lock, flags);

                                                                                return ret;
                                                                            }
                                                                        }

                                                                        /* May have received a reset since last time we checked */
                                                                        ret = -ESHUTDOWN;
                                                                        spin_lock_irqsave(&udc->lock, flags);
                                                                        if (ep->ep.desc) { //
                                                                            list_add_tail(&req->queue, &ep->queue);

                                                                            if ((!ep_is_control(ep) && ep->is_in) ||
                                                                                (ep_is_control(ep)
                                                                                    && (ep->state == DATA_STAGE_IN
                                                                                        || ep->state == STATUS_STAGE_IN))) { //
                                                                                usba_ep_writel(ep, CTL_ENB, USBA_TX_PK_RDY);
                                                                            }
                                                                            ret = 0;
                                                                        }
                                                                        spin_unlock_irqrestore(&udc->lock, flags);

                                                                        return ret;
                                                                    }
                                                                }

                                                                return 0;
                                                            }

                                                            return 0;
                                                        }
                                                    }

                                                    /* when we return, be sure our power usage is valid */
                                                    power = c->MaxPower ? c->MaxPower : CONFIG_USB_GADGET_VBUS_DRAW;
                                                done:
                                                    //usb_gadget_vbus_draw(gadget, power);

                                                    return result;
                                                }
                                                spin_unlock(&cdev->lock);
                                                break;
                                            }

                                            /* respond with data transfer before status phase? */
                                            if (value >= 0 && value != USB_GADGET_DELAYED_STATUS) {
                                                req->length = value;
                                                req->context = cdev;
                                                req->zero = value < w_length;
                                                value = composite_ep0_queue(cdev, req, GFP_ATOMIC);
                                                static int composite_ep0_queue(struct usb_composite_dev *cdev,
                                                        struct usb_request *req, gfp_t gfp_flags)
                                                {
                                                    int ret;

                                                    ret = usb_ep_queue(cdev->gadget->ep0, req, gfp_flags);
                                                    if (ret == 0) {
                                                        if (cdev->req == req) {
                                                            cdev->setup_pending = true;
                                                        }
                                                    }

                                                    return ret;
                                                }
                                            }

                                            /* device either stalls (value < 0) or reports success */
                                            return value;
                                        }
                                        spin_lock(&udc->lock);
                                    }

                                    return retval;
                                }
                            }

                            DBG(DBG_BUS, "req %02x.%02x, length %d, state %d, ret %d\n",
                                crq.crq.bRequestType, crq.crq.bRequest,
                                le16_to_cpu(crq.crq.wLength), ep->state, ret);
                        }
                    }
